如何在Scala中定义泛型类型?

Cri*_*riu 6 scala slick

在Slick 2中,我们可以映射这样的表:

case class Cooler(id: Option[Int], minTemp: Option[Double], maxTemp: Option[Double])

/**
 * Define table "cooler".
 */
class Coolers(tag: Tag) extends Table[Cooler](tag, "cooler") {
  def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
  def minTemp = column[Double]("min_temp", O.Nullable)
  def maxTemp = column[Double]("max_temp", O.Nullable)

  def * = (id.?, minTemp.?, maxTemp.?) <> (Cooler.tupled, Cooler.unapply _)
}

object Coolers {
  val tableQuery = TableQuery[Coolers]
}
Run Code Online (Sandbox Code Playgroud)

因为我有很多的表,我想为它们定义通用的方法,如find,delete,update所以我必须要定义一个超类这些方法从哪里致以对象(object Coolers extends TableUtils[Coolers, Cooler]).为了定义这些方法,我需要tableQuery在这个超类中移出我的对象,所以我尝试了它:

abstract class TableUtils[T <: Table[A] , A] {

val tableQuery = TableQuery[T]  

}
Run Code Online (Sandbox Code Playgroud)

但我收到tableQuery定义错误:

class type required but T found

有谁知道我做错了什么?

Rég*_*les 11

当你这样做,TableQuery[T]你实际上是在呼叫TableQuery.apply,这实际上是一个宏.

此宏的主体尝试实例化T,但在您的情况下,T已成为编译器不知道如何实例化的(未知)类型参数.问题类似于尝试编译:

def instantiate[T]: T = new T
// Does not compile ("class type required but T found")
Run Code Online (Sandbox Code Playgroud)

净效果是TableQuery.apply只能用于混凝土类型.

可以变通解决使用类型的类来捕获调用TableQuery.apply同一个隐含的宏观沿(在这里具体类型是已知的点)提供这种类型的类的实例.然后你会有类似的东西:

abstract class TableUtils[T <: Table[A] : TableQueryBuilder, A] {
  val tableQuery = BuildTableQuery[T]
}
Run Code Online (Sandbox Code Playgroud)

TableQueryBuilder类型类在哪里,并且BuildTableQuery是它的替代版本TableQuery.apply将转发到TableQueryBuilder实例以执行实际实例化.

我在这里添加了一个实现作为另一个答案的一部分.

tableQuery每个具体派生类声明为抽象值并定义它将更容易(如果不太方便)TableUtils:

abstract class TableUtils[T <: Table[A] , A] {
  val tableQuery: TableQuery[T, T#TableElementType]
  // define here your helper methods operating on `tableQuery`
}
object Coolers extends TableUtils[Coolers, Cooler] {
  val tableQuery = TableQuery[Coolers]
}
Run Code Online (Sandbox Code Playgroud)