3

私はSquerylの設定を一般化しようとしています(Slickは同じ問題を引き起こします)。多くの一般的なメソッドに対して、すべてのケース クラスに明示的に名前を付ける必要は避けたいと考えています。

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 Macros は間違ったツールですか?

4

2 に答える 2

4

残念ながら、reifyユースケースには十分な柔軟性がありませんが、良いニュースがあります. マクロの楽園 (そしておそらく 2.11.0) では、準引用符と呼ばれるツリーを構築するためのより優れたツールがあります: 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()

準引用符は 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 に答える