这个小例子,调用代码看起来编译(Eclipse的靛蓝SR2,斯卡拉v2.10.20),但包含调用代码项目标有红色的叉号(我不清楚如何获得进一步诊断此)。 无级文件生成。 如果我有一些文字比如1代替param.value,调用代码编译。
这是一个已知的问题? 有没有解决办法?
def myMacro( param : Int ): Int = macro myMacroImpl( param )
def myMacroImpl(c: Context)(param: c.Expr[Int]): c.Expr[Int] = {
import c.universe._
c.Expr( Literal( Constant( param.value ) ) )
}
首先,宏定义的语法并不需要(或允许)您指定的参数宏的实现方法,使你的代码不应该编译,即使在实现文字。 见下面的正确的语法我的例子。
接下来, Expr.value
是不幸的是谎言。 回想一下参数给宏方法是可变的情况。 该变量的值是不是(在一般情况下不能 )在编译时已知的,但你试图与该值的编译时间常量。 它只是从根本行不通的。
你有几个选项,这取决于你想做什么可能或可能不适用。 假设我们需要添加一个到param
值,并返回结果,例如。 如果我们想加入在编译时发生,我们不得不抛出一个(编译时)的异常时,我们没有得到一个编译时的文字:
def myMacro(param: Int): Int = macro myMacroImpl
def myMacroImpl(c: Context)(param: c.Expr[Int]): c.Expr[Int] = {
import c.universe._
val p = param.tree match {
case Literal(Constant(p: Int)) => p
case _ => c.abort(c.enclosingPosition, "param must be a literal value!")
}
c.literal(p + 1) // Or, equivalently: c.Expr(Literal(Constant(p + 1))
}
另一种选择是围绕打造一棵树param
表达。 例如,下文中也将返回后继param
,但在运行时执行相加,并且该方法可以处理非文字形参:
def myMacro(param: Int): Int = macro myMacroImpl
def myMacroImpl(c: Context)(param: c.Expr[Int]): c.Expr[Int] = {
import c.universe._
c.Expr(
Apply(Select(param.tree, newTermName("$plus")), c.literal(1).tree :: Nil)
)
}
我们只是不会得到编译时除了和任意param
表达,虽然。