假设我想编写一个需要知道(在编译时)它的参数的实际值的宏。如果用户以这种方式调用它:
mymacro(42)
然后传递给宏的树将是Literal(Constant(42))
,宏可以像这样模式匹配:
tree match { case Literal(Constant(x: Int)) => x }
我 希望知道任意表达式的值:
mymacro(40 + numWindowsOpen()) // not allowed; macro should fail at compile time
但是,我想允许这样的表达式:
val answer = 42 // val is immutable
mymacro(answer)
树是Ident(TermName("answer"))
,或者像这样:
mymacro(40 + 2)
树为Apply(Select(Literal(Constant(40)), TermName("$plus")), List(Literal(Constant(2))))
。
问题:有没有办法将上述所有三个静态可计算的例子简化为相同的表格?
我的主张是,所有三棵树在某种意义上都是等同于。
我知道在编译时可以评估一棵树,例如:
val tree = q"40 + 2"
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
val toolbox = runtimeMirror(getClass.getClassLoader).mkToolBox()
toolbox.eval(tree) // returns 42
这可能是一个选项,但它有点不能令人满意,因为表达式中的任何副作用都将在编译时执行。实际上,它甚至可能返回40 + numWindowsOpen()
树的值,这直觉上并不是静态值。