How to define generic type in Scala?

佐手、 提交于 2019-12-03 15:03:54
Régis Jean-Gilles

When you do TableQuery[T] you are in fact calling TableQuery.apply, which is actually a macro.

The body of this macro tries to instantiate T, but in your case T has become an (unknown) type parameter that the compiler does not know how to instantiate. The problem is similar to trying to compile this:

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

The net effect is that TableQuery.apply can only be used on concrete types.

You could work around that using a type class to capture the call to TableQuery.apply (at the point where the concrete type is known) along with an implicit macro to provide an instance of this type class. Then you would have something like:

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

Where TableQueryBuilder is the type class and BuildTableQuery is an alternate version of TableQuery.apply that will forward to the TableQueryBuilder instance to perform the actual instantiation.

I've added an implementation as part of another answer here.

It will be much easier (if less convenient) to just declare tableQuery as an abstract value and define it in every concrete derived class of 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]
}

Here is one solution:

At first, define this to avoid class type issue..

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

  lazy val db = Database.forConfig(path)

  def query = TableQuery[T](cons)
}

Then use it this way, Post is sub class of 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)

}

This solution tested ok in slick 3.x, and Play slick 1.x, since the slick 2.0 Query.scala comply to slick 3.0 Query.scala, this might work at 2 too.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!