我尝试实现documentation中所述的Scala宏注释示例。我设法在使用宏注释的实际项目之前对其进行了编译,即@compileTimeOnly("enable macro paradise to expand macro annotations")
没有被触发,这意味着该宏注释在使用前便已编译。到目前为止一切顺利。
但是,当我在实际项目中注释某些值时,如下所示:
@identity val foo: Double = 1.1
@identity val bar: String = "bar"
然后,我希望在运行主项目时发生以下打印(通过前面链接的宏注释示例):
(<empty>,List(val foo: Double = 1.1))
(<empty>,List(val bar: String = "bar"))
这是让我感到困惑的地方,在运行主项目时不会进行打印。但是,在编译主项目时,它确实会瞬间显示吗?
(我正在使用IntelliJ IDEA和Scala 2.12.8)
答案 0 :(得分:2)
我设法在使用宏注释的实际项目之前对其进行了编译,即@compileTimeOnly(“启用宏天堂以扩展宏注释”)没有被触发,这意味着在使用宏注释之前已对其进行编译>
否,@compileTimeOnly
被触发将意味着在使用注释进行编译的代码之后存在注释。因此,如果不触发该宏,则表明该宏已在编译期间执行。而且由于println
在宏的主体中,而不是在转换后的代码中,因此您可以看到输出。
如果要在运行项目时进行打印,则需要修改包含转换后代码的返回值,即示例中的最后两行:
val outputs = expandees
c.Expr[Any](Block(outputs, Literal(Constant(()))))
使用quasiquotes或directly manipulating ASTs。
未经测试,但使用准引用应该可以正常工作
object identityMacro {
def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
val inputs = annottees.map(_.tree).toList
val (annottee, expandees) = inputs match {
case (param: ValDef) :: (rest @ (_ :: _)) => (param, rest)
case (param: TypeDef) :: (rest @ (_ :: _)) => (param, rest)
case _ => (EmptyTree, inputs)
}
val stringToPrint = (annottee, expandees).toString
c.Expr[Any](q"""
println($stringToPrint)
$expandees
()
""")
}
}