使用Slick Table的Scala类型推断

ka4*_*eli 6 types scala type-inference slick

有这样的模型(简化):

case class User(id:Int,name:String)
case class Address(id:Int,name:String)
...
Run Code Online (Sandbox Code Playgroud)

Slick(2.1.0版)表映射:

class Users(_tableTag: Tag) extends Table[User](_tableTag, "users") with WithId[Users, User] {`
  val id: Column[Int] = column[Int]("id", O.AutoInc, O.PrimaryKey)
  ...
}
trait WithId[T, R] {
  this: Table[R] =>
  def id: Column[Int]
}
Run Code Online (Sandbox Code Playgroud)

混合特性WithId我想用列实现不同表的通用DAO方法id: Column[Int] (我希望方法findById与两者UserAddress表映射一起使用)

trait GenericSlickDAO[T <: WithId[T, R], R] {
  def db: Database

  def findById(id: Int)(implicit stk: SlickTableQuery[T]): Option[R] = db.withSession { implicit session =>
    stk.tableQuery.filter(_.id === id).list.headOption
  }

trait SlickTableQuery[T] {
  def tableQuery: TableQuery[T]
}

object SlickTableQuery {
  implicit val usersQ = new SlickTableQuery[Users] {
    val tableQuery: Table Query[Users] = Users
  }
}
Run Code Online (Sandbox Code Playgroud)

问题是findById不编译:

错误:(13,45)类型不匹配; found:需要选项[T#TableElementType]:Option [R] stk.tableQuery.filter(_.id === id).list.headOption

我认为它T是类型的WithId[T, R],同时也是类型Table[R].Slick实现了Table这样的类型,如果那样的X=Table[Y]X#TableElementType=Y.

所以在我的情况下T#TableElementType=R,Option[T#TableElementType]应该推断,Option[R]但事实并非如此.我哪里错了?

edi*_*edi 3

您关于WithId[T, R]类型的假设Table[R]是错误的。中的自类型注释WithId[T, R]只需要Table[R]混合 a ,但这并不意味着它WithId[T, R]Table[R].

我认为您将声明与最终需要成为 a 实例的WithId实例混淆了。WithIdTable

特征中的上限类型约束GenericSlickDAO也不能保证您的属性WithId成为 的实例Table,因为任何类型都是其自身的子类型。

有关自我类型和子类型之间差异的更详细解释,请参阅此问题。