【问题标题】:Infer multiple generic types in an abstract class that should be available to the compiler在抽象类中推断编译器应该可以使用的多个泛型类型
【发布时间】:2014-05-10 22:13:53
【问题描述】:

我正在为我的 play2/slick2 项目开发一个抽象的 CRUD-DAO。为了获得方便的类型安全主 ID,我使用 Unicorn 作为光滑 MappedToColumnBaseType 之上的额外抽象和便利。

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])

这对我来说似乎非常多余。我能够提供来自TtableNamequery,在我自己的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 中是否有可能以某种方式推断类型 IA 以使如下签名成为可能? (Users 是一个扩展 IdTable 的类)

class UserDao extends AbstractIdDao[Users]

如果没有运行时反射,这可能吗?如果仅通过运行时反射:我如何在类定义中使用 Manifest 以及对响应式应用程序的性能影响有多大?

另外,由于我对这门语言还很陌生并且自己工作:这在 scala 中是不是很好?

感谢您的帮助。随意批评我的问题和英语。改进当然会提交给 Unicorn git-repo

编辑: 实际上,TableQuery[T].baseTableRow.tableName, TableQuery[T] 不起作用,因为错误 class type required but T found,IDEA 表面上很好,但 scalac 不是。

【问题讨论】:

  • 有关TableQuery[T].baseTableRow.tableName 错误的解释,请参阅此其他答案。错误是在宏内部发出的,这可能是 IntelliJ 无法检测到它的原因。

标签: scala generics inheritance slick-2.0


【解决方案1】:

至于您的第一个问题,我在使用 Slick 时也遇到过这个问题。但是如果你仔细想想,你会发现你不能在编译时这样做。这是因为此类型信息是指定类型参数之间的关系 所必需的。如果您不这样做,您将能够构造类型没有意义的BaseIdRepository 类,例如IdTables,其中表格不代表投影。由于每个关系都需要名称,因此需要 3 个命名类型参数。如果省略第一个,则可以在没有包含 Id 的投影的情况下构造 IdRepository;如果省略第二个,则可能有一个没有 ID 列的表;如果省略第三个,则可以查询没有表和带有 ID 的投影组合的表。您的应用程序中可能没有定义当前会破坏任何这些规则的类型,但编译器不知道这一点。提供正确的类型信息是不可避免的。

至于你的第二个问题,非常不建议仅仅因为你认为语法冗长而使用反射。如果您可以通过简单地提供类型参数来保证类型安全,我建议您这样做。以这种方式编写 Scala 的品味和风格都非常糟糕。具有讽刺意味的是,在 Unicorn 中使用类型安全 ID,然后通过反射绕过其类型安全。

此外,Manifest 不是您想要的 :清单不允许您向编译器提供 less 类型信息,它只允许您更灵活地指定您这样做的位置。它允许您在编译时利用编译器的类型知识来规避类型擦除引入的一些问题。您在这里遇到的问题与类型擦除无关,因此 Manifests 将不起作用。最后,运行时反射在这里对你没有多大帮助,因为如果你还没有提供类型信息,Slick 的内部函数将不允许你进行编译。

所以是的,你想要的是不可能的。 Scala(和 Slick)在编译时需要完整的信息,没有任何技巧可以有效地规避这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多