【发布时间】:2013-06-22 18:30:26
【问题描述】:
假设我有一个特征 Foo,我用初始值 i 进行实例化
val foo = new Foo(6) // class Foo(i: Int)
我后来调用了secondMethod,而后者又调用了myMacro
foo.secondMethod(7) // def secondMethod(j: Int) = macro myMacro
那么,myMacro如何找到i的初始值(6)?
我没有成功使用c.prefix、c.eval(...) 等进行正常编译反射,而是找到了一个 2-project 解决方案:
项目 B:
object CompilationB {
def resultB(x: Int, y: Int) = macro resultB_impl
def resultB_impl(c: Context)(x: c.Expr[Int], y: c.Expr[Int]) =
c.universe.reify(x.splice * y.splice)
}
项目A(取决于项目B):
trait Foo {
val i: Int
// Pass through `i` to compilation B:
def apply(y: Int) = CompilationB.resultB(i, y)
}
object CompilationA {
def makeFoo(x: Int): Foo = macro makeFoo_impl
def makeFoo_impl(c: Context)(x: c.Expr[Int]): c.Expr[Foo] =
c.universe.reify(new Foo {val i = x.splice})
}
我们可以创建一个Foo 并使用普通实例化或makeFoo 之类的宏来设置i 值。第二种方法允许我们在第一次编译时在编译时自定义Foo,然后在第二次编译中进一步自定义其对输入的响应(在本例中为i)!在某种程度上,我们获得了“元元”能力(或“超形上学”能力;-)
通常我们需要在范围内有 foo 以内省 i(例如 c.eval(...))。但是通过将i 值保存在Foo 对象中,我们可以随时访问它,并且可以在任何地方实例化Foo:
object Test extends App {
import CompilationA._
// Normal instantiation
val foo1 = new Foo {val i = 7}
val r1 = foo1(6)
// Macro instantiation
val foo2 = makeFoo(7)
val r2 = foo2(6)
// "Curried" invocation
val r3 = makeFoo(6)(7)
println(s"Result 1 2 3: $r1 $r2 $r3")
assert((r1, r2, r3) ==(42, 42, 42))
}
我的问题
我可以在我的示例宏中找到i,而无需这种双重编译技巧吗?
【问题讨论】:
标签: scala scala-macros