Вывод нескольких универсальных типов в абстрактном классе, который должен быть доступен компилятору.

Я работаю над абстрактным CRUD-DAO для моего проекта play2/slick2. Чтобы иметь удобные первичные идентификаторы, безопасные для типов, я использую Unicorn в качестве дополнительной абстракции и удобства поверх сликов MappedTo и ColumnBaseType.

Unicorn предоставляет базовый класс CRUD-DAO BaseIdRepository, который я хочу расширить для конкретных нужд проекта. Подпись класса

class BaseIdRepository[I <: BaseId, A <: WithId[I], T <: IdTable[I, A]]
  (tableName: String, val query: TableQuery[T])
  (implicit val mapping: BaseColumnType[I])
  extends BaseIdQueries[I, A, T]

Это приводит к тому, что реализации DAO выглядят примерно так:

class UserDao extends 
  BaseIdRepository[UserId, User, Users]("USERS", TableQuery[Users])

Мне это кажется ужасно излишним. Я смог поставить tableName и query из T, предоставив мне следующую подпись на моем собственном Abstract DAO.

abstract class AbstractIdDao[I <: BaseId, A <: WithId[I], T <: IdTable[I, A]] 
  extends BaseIdRepository[I,A,T](TableQuery[T].baseTableRow.tableName, TableQuery[T])

Возможно ли в Scala каким-то образом вывести типы I и A, чтобы сделать возможной подпись, подобную следующей? (Users — это класс, расширяющий IdTable)

class UserDao extends AbstractIdDao[Users]

Возможно ли это без времени выполнения? Если только с помощью отражения во время выполнения: как использовать манифест в определении класса и насколько велико влияние производительности в реактивном приложении?

Кроме того, поскольку я новичок в языке и работаю самостоятельно: это вообще хорошая практика в scala?

Спасибо за помощь. Не стесняйтесь критиковать мой вопрос и английский язык. Улучшения, конечно же, будут отправлены в git-repo Unicorn.

EDIT: На самом деле, TableQuery[T].baseTableRow.tableName, TableQuery[T] не работает из-за ошибки требуется тип класса, но T найден, IDEA внешне устраивала, а scalac — нет.


person Floscher    schedule 31.03.2014    source источник
comment
См. этот другой ответ для объяснения ошибки на TableQuery[T].baseTableRow.tableName. Ошибка возникает внутри макроса, вероятно, поэтому IntelliJ не может ее обнаружить.   -  person Régis Jean-Gilles    schedule 25.04.2014


Ответы (1)


Что касается вашего первого вопроса, я столкнулся с этим и при работе со Сликом. Но если вы подумаете об этом, вы увидите, что вы не можете сделать это во время компиляции. Это связано с тем, что эта информация о типе необходима для указания отношений между вашими параметрами типа. Если бы вы этого не сделали, вы могли бы создавать классы BaseIdRepository, где типы не имеют смысла, например IdTables, где таблица не представляет проекцию. Поскольку вам нужны имена для каждого из этих отношений, вам нужны 3 параметра именованного типа. Если вы опустите первый, можно построить IdRepository без проекции, содержащей идентификатор; если вы опустите второй, возможно иметь таблицу без столбца идентификатора; и если вы опустите третий, можно запросить таблицы, у которых нет этой комбинации таблицы и проекции с идентификатором. Возможно, в вашем приложении не определены типы, которые нарушили бы какое-либо из этих правил, но компилятор об этом не знает. Предоставление надлежащей информации о типе неизбежно.

Что касается вашего второго вопроса, крайне не рекомендуется использовать отражение только потому, что вы считаете, что синтаксис слишком многословен. Если вы можете гарантировать безопасность типов, просто предоставляя параметры типа, я бы посоветовал вам это сделать. Плохой вкус и стиль писать на Scala таким образом. Было бы иронично использовать безопасные для типов идентификаторы с Unicorn, а затем взломать его безопасность типов с помощью отражения.

Кроме того, Manifest — это не то, что вам нужно: манифест не позволяет вам предоставлять компилятору less информацию о типе, он только позволяет вам более гибко указывать где вы это делаете. Это позволяет вам использовать знания компилятора о типах во время компиляции, чтобы обойти некоторые проблемы, возникающие при стирании типов. Проблема, с которой вы сталкиваетесь здесь, не имеет ничего общего со стиранием типов, поэтому Manifests не будет работать. Наконец, отражение во время выполнения не сильно вам здесь поможет, потому что внутренние функции Slick не позволят вам скомпилировать, если вы еще не предоставили информацию о типе.

Так что да, то, что вы хотите, невозможно. Scala (и Slick) нуждаются в полной информации во время компиляции, и никакой трюк не поможет обойти это.

person DCKing    schedule 25.04.2014