如何在 Scala 宏中创建 class 或对象?
How do I create a class or object in Scala Macros?
我正在尝试使用宏从案例 class 生成伴随对象,但我很难找到如何完成此操作的任何示例。
例如:
case class Person(name: String, age: Int, id: Option[Int] = None)
如果我这样做:
object PersonTable extends TypedTable[Person]
我希望它生成:
object PersonTable extends Table("PERSON") {
val name = column[String]("NAME")
val age = column[Int]("AGE")
val id = column[Option[Int]]("ID")
}
此外,我希望能够扩展它并添加其他字段:
object PersonTable extends TypedTable[Person] {
val created = column[Timestamp]("TIMESTAMP")
}
它会生成:
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")
}
编辑
阅读宏注释后(感谢 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")
}
}
}
然后尝试像这样使用它:
@table[String] object MyCoolObject
MyCoolObject.test()
第一行没问题,第二行说找不到测试方法。我如何才能使测试方法可见?
不幸的是很难在网上找到很好的宏示例 - 特别是对于 2.11。我终于能够让一切正常工作,所以我想为以后遇到同样问题的任何人提供代码 link。
再次感谢 Eugene 和 Mario 的出色回答,让我找到了答案。
我正在尝试使用宏从案例 class 生成伴随对象,但我很难找到如何完成此操作的任何示例。
例如:
case class Person(name: String, age: Int, id: Option[Int] = None)
如果我这样做:
object PersonTable extends TypedTable[Person]
我希望它生成:
object PersonTable extends Table("PERSON") {
val name = column[String]("NAME")
val age = column[Int]("AGE")
val id = column[Option[Int]]("ID")
}
此外,我希望能够扩展它并添加其他字段:
object PersonTable extends TypedTable[Person] {
val created = column[Timestamp]("TIMESTAMP")
}
它会生成:
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")
}
编辑
阅读宏注释后(感谢 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")
}
}
}
然后尝试像这样使用它:
@table[String] object MyCoolObject
MyCoolObject.test()
第一行没问题,第二行说找不到测试方法。我如何才能使测试方法可见?
不幸的是很难在网上找到很好的宏示例 - 特别是对于 2.11。我终于能够让一切正常工作,所以我想为以后遇到同样问题的任何人提供代码 link。
再次感谢 Eugene 和 Mario 的出色回答,让我找到了答案。