【发布时间】:2014-01-27 18:48:28
【问题描述】:
在 Scala 中编写宏时,准引号可以简化很多事情。但是我注意到,每次触发 SBT 中的编译时,都可以重新编译包含 quasiquotes 的宏,即使宏实现和它的任何调用站点都没有更改并且需要重新编译。
这似乎不会发生,如果 quasiquotes 中的代码相当简单,它似乎只有在依赖于另一个类时才会发生。我注意到用“reify”重写所有内容似乎可以解决重新编译问题,但我无法在没有准引号的情况下重写最后一部分......
我的宏通过在编译期间创建包装函数来避免启动时反射。
我有以下课程:
object ExportedFunction {
def apply[R: Manifest](f: Function0[R], fd: FunctionDescription): ExportedExcelFunction = new ExcelFunction0[R] {
def apply: R = f()
val functionDescription = fd
}
def apply[T1: Manifest, R: Manifest](f: Function1[T1, R], fd: FunctionDescription): ExportedExcelFunction = new ExcelFunction1[T1, R] {
def apply(t1: T1): R = f(t1)
val functionDescription = fd
}
... and so on... until Function17...
}
然后我分析object 并使用所描述的接口导出任何成员函数,如下所示:
def export(registrar: FunctionRegistrar,
root: Object,
<...more args...>) = macro exportImpl
def exportImpl(c: Context)(registrar: c.Expr[FunctionRegistrar],
root: c.Expr[Object],
<...>): c.Expr[Any] = {
import c.universe._
<... the following is simplified ...>
root.typeSignature.members.flatMap {
case x if x.isMethod =>
val method = x.asMethod
val callee = c.Expr(method))
val desc = q"""FunctionDescription(<...result from reflective lookup...>)"""
val export = q"ExportedFunction($callee _, $desc)"
q"$registrar.+=({$export})"
我可以用 reify 重写第一行和最后一行,但我无法重写第二行,我最好的方法是使用 quasiquotes:
val export = reify {
...
ExportedFunction(c.Expr(q"""$callee _"""), desc)
...
}.tree
但这会导致:
overloaded method value apply with alternatives... cannot be applied to (c.Expr[Nothing], c.universe.Expr[FunctionDescription])
我认为编译器缺少隐式,或者该代码可能仅适用于具有固定数量参数的函数,因为它需要在宏编译时知道该方法有多少参数?但是,如果所有内容都使用 quasiquotes 编写,则它可以工作...
【问题讨论】: