在抽象类中推断应该可供编译器使用的多个泛型类型

时间:2014-03-31 14:10:32

标签: scala generics inheritance slick-2.0

我正在为我的play2 / slick2项目开发一个抽象的CRUD-DAO。为了获得方便的类型安全的主要ID,我使用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提供queryT,在我自己的抽象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]不起作用,因为错误类类型需要但是找到了,IDEA表面上很好,scalac不是。

1 个答案:

答案 0 :(得分:0)

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

关于你的第二个问题,因为你认为语法是冗长的,所以非常不可能采用反射。如果您只需提供类型参数就可以保证类型安全,我建议您这样做。以这种方式编写Scala是非常糟糕的品味和风格。对Unicorn采用类型安全ID并随后通过反射破解其类型安全性将具有讽刺意味。

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

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