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

时间:2013-11-20 07:50:39

标签: 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]
}

因为我有很多表,我想为它们定义泛型方法,比如finddeleteupdate所以我必须在超类中定义这些方法。在哪里扩展我的对象(object Coolers extends TableUtils[Coolers, Cooler])。为了定义这些方法,我需要tableQuery从这个超类中移出我的对象,所以我尝试了它:

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

val tableQuery = TableQuery[T]  

}

但我在tableQuery定义上收到错误:

class type required but T found

有人知道我做错了吗?

2 个答案:

答案 0 :(得分:11)

当您执行TableQuery[T]时,您实际上正在呼叫TableQuery.apply is actually a macro

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

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

净效应是TableQuery.apply只能用于具体类型。

可以解决using a type class to capture the call to TableQuery.apply(在具体类型已知的位置)以及隐式宏来提供此类型类的实例。然后你会有类似的东西:

abstract class TableUtils[T <: Table[A] : TableQueryBuilder, A] {
  val tableQuery = BuildTableQuery[T]
}

其中TableQueryBuilder是类型类,BuildTableQueryTableQuery.apply的备用版本,它将转发到TableQueryBuilder实例以执行实际的实例化。

我添加了一个实现作为another answer here的一部分。

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

答案 1 :(得分:0)

这是一个解决方案:

首先,定义它以避免类类型问题..

class Service[T <: Table[_]](path: String, cons: Tag => T){

  lazy val db = Database.forConfig(path)

  def query = TableQuery[T](cons)
}

然后以这种方式使用它,Post是Table的子类:

object Abcd {

  object Def extends Service[Post]("mydb", abc) {



    def test = {


      //db

      val q = query.drop(1).take(20)
      val r = db.run(q.result)

      println(q.result.statements.head)
      println(r)

      r

    }
  }

  private def abc(tag: Tag) = new Post(tag)

}

此解决方案在光滑的3.x和Play slick 1.x中测试正常,因为光滑的2.0 Query.scala符合光滑的3.0 Query.scala,这也可能在2处工作。