3

我正在尝试概括设置 Squeryl(Slick 提出了同样的问题 AFAIK)。我想避免必须为许多通用方法显式命名每个案例类。

table[Person]
table[Bookmark]
etc.

这也适用于生成索引,并为每个案例类围绕 CRUD 方法创建包装器方法。

所以理想情况下我想做的是有一个类列表并将它们制作成表,添加索引并添加一个包装器方法:

val listOfClasses = List(classOf[Person], classOf[Bookmark])
listOfClasses.foreach(clazz => {
  val tbl = table[clazz]
  tbl.id is indexed
  etc.
})

我认为 Scala 宏将适用于此处,因为我认为您不能将值作为类型参数。我还需要为每种类型的表单生成方法:

def insert(model: Person): Person = persons.insert(model)

我对宏的示例有所了解,但我不知道如何生成通用数据结构。

我得到了这个简单的例子来说明我想要什么:

def makeList_impl(c: Context)(clazz: c.Expr[Class[_]]): c.Expr[Unit] = {
  import c.universe._

  reify {
    println(List[clazz.splice]()) // ERROR: error: type splice is not a member of c.Expr[Class[_]]
  }
}

def makeList(clazz: Class[_]): Unit = macro makeList_impl

我该怎么做呢?还是 Scala 宏是错误的工具?

4

2 回答 2

4

不幸的是,reify对于您的用例来说不够灵活,但有个好消息。在宏观天堂(很可能在 2.11.0 中)我们有一个更好的工具来构建树,称为 quasiquotes:http ://docs.scala-lang.org/overviews/macros/quasiquotes.html 。

scala> def makeList_impl(c: Context)(clazz: c.Expr[Class[_]]): c.Expr[Any] = {
     | import c.universe._
     | val ConstantType(Constant(tpe: Type)) = clazz.tree.tpe
     | c.Expr[Any](q"List[$tpe]()")
     | }
makeList_impl: (c: scala.reflect.macros.Context)(clazz: c.Expr[Class[_]])c.Expr[Any]

scala> def makeList(clazz: Class[_]): Any = macro makeList_impl
defined term macro makeList: (clazz: Class[_])Any

scala> makeList(classOf[Int])
res2: List[Int] = List()

scala> makeList(classOf[String])
res3: List[String] = List()

Quasiquotes 甚至可以在 2.10.x 中使用,只需对构建过程进行微调(http://docs.scala-lang.org/overviews/macros/paradise.html#macro_paradise_for_210x),因此您可能想尝试一下。

于 2013-06-04T12:30:41.763 回答
1

这可能无法满足您的所有需求,但它可能会有所帮助:

方法的签名table如下所示:

protected def table[T]()(implicit manifestT: Manifest[T]): Table[T]

如您所见,它需要隐式Manifest对象。该对象由编译器自动传递并包含有关 type 的信息T。这实际上是 Squeryl 用来检查数据库实体类型的方法。

您可以像这样显式传递这些清单:

val listOfManifests = List(manifest[Person], manifest[Bookmark])
listOfManifests.foreach(manifest => {
  val tbl = table()(manifest)
  tbl.id is indexed
  etc.
})

不幸tbl的是,这段代码的类型类似于Table[_ <: CommonSupertypeOfAllGivenEntities]这意味着对它的所有操作都必须与数据库实体的具体类型无关。

于 2013-06-03T17:14:13.003 回答