如何在Scala宏中创建类或对象?

dar*_*rog 4 macros scala

我试图使用Macros从案例类中生成一个伴随对象,但是我很难找到任何有关如何完成此操作的示例。

例如:

case class Person(name: String, age: Int, id: Option[Int] = None)
Run Code Online (Sandbox Code Playgroud)

如果我做:

object PersonTable extends TypedTable[Person]
Run Code Online (Sandbox Code Playgroud)

我希望它生成:

object PersonTable extends Table("PERSON") {
  val name = column[String]("NAME")
  val age = column[Int]("AGE")
  val id = column[Option[Int]]("ID")
}
Run Code Online (Sandbox Code Playgroud)

此外,我希望能够扩展它并添加其他字段:

object PersonTable extends TypedTable[Person] {
  val created = column[Timestamp]("TIMESTAMP")
}
Run Code Online (Sandbox Code Playgroud)

它会生成:

object PersonTable extends Table("PERSON") {
  val name = column[String]("NAME")
  val age = column[Int]("AGE")
  val id = column[Option[Int]]("ID")
  val created = column[Timestamp]("TIMESTAMP")
}
Run Code Online (Sandbox Code Playgroud)

编辑

在阅读了有关宏注释(感谢Eugene和Mario)之后,我创建了以下代码:

class table[T] extends StaticAnnotation {
  def macroTransform(annottees: Any*) = macro TableGenerator.impl
}

object TableGenerator {
  def impl(c: whitebox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
    import c.universe._

    def modifiedObject(objectDef: ModuleDef): c.Expr[Any] = {
      val ModuleDef(_, objectName, template) = objectDef
      val ret = q"""
object $objectName {
  def test() = println("Wahoo!")
}
      """
      c.Expr[Any](ret)
    }

    annottees.map(_.tree) match {
      case (objectDecl: ModuleDef) :: _ => modifiedObject(objectDecl)
      case x => c.abort(c.enclosingPosition, s"@table can only be applied to an object, not to $x")
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后尝试像这样使用它:

@table[String] object MyCoolObject
MyCoolObject.test()
Run Code Online (Sandbox Code Playgroud)

第一行工作正常,但第二行表示找不到测试方法。如何使测试方法可见?

dar*_*rog 6

不幸的是,在网上很难找到良好的Macros示例-尤其是对于2.11。我终于能够使所有工作正常进行,因此我想为以后遇到相同问题的任何人提供代码链接。

https://github.com/outr/scalarelational/blob/master/mapper/src/main/scala/org/scalarelational/mapper/typedTable.scala

再次感谢尤金(Eugene)和马里奥(Mario)的出色回答,促使我找到了答案。