我正在尝试使用scala宏编写代理宏。我希望能够代理特征X并返回X的实例,为X的所有方法调用一个函数。
这是我到目前为止所做的。假设我们要代理特征TheTrait(在下面定义),我们可以运行ProxyMacro.proxy传递一个函数,该函数将被调用代理方法的所有调用。
trait TheTrait
{
def myMethod(x: String)(y: Int): String
}
val proxy = ProxyMacro.proxy[TheTrait] {
case ("myMethod", args) =>
"ok"
}
println(proxy.myMethod("hello")(5))
到目前为止的实施是:
package macrotests
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
object ProxyMacro
{
type Implementor = (String, Any) => Any
def proxy[T](implementor: Implementor): T = macro impl[T]
def impl[T: c.WeakTypeTag](c: Context)(implementor: c.Expr[Implementor]): c.Expr[T] = {
import c.universe._
val tpe = weakTypeOf[T]
val decls = tpe.decls.map { decl =>
val termName = decl.name.toTermName
val method = decl.asMethod
val params = method.paramLists.map(_.map(s => internal.valDef(s)))
val paramVars = method.paramLists.flatMap(_.map { s =>
internal.captureVariable(s)
internal.referenceCapturedVariable(s)
})
q""" def $termName (...$params) = {
$implementor (${termName.toString}, List(..${paramVars}) ).asInstanceOf[${method.returnType}]
}"""
}
c.Expr[T] {
q"""
new $tpe {
..$decls
}
"""
}
}
}
但是有一个问题。由于List(.. $ {paramVars}),这不会编译。这应该只创建一个包含方法参数的所有值的列表。 但是我在那一行得到了编译问题(不值得粘贴)。
如何将方法参数列表转换为其值?
答案 0 :(得分:2)
showInfo在调试宏
时很有用 def showInfo(s: String) =
c.info(c.enclosingPosition, s.split("\n").mkString("\n |---macro info---\n |", "\n |", ""), true)
变化
val paramVars = method.paramLists.flatMap(_.map { s =>
internal.captureVariable(s)
internal.referenceCapturedVariable(s)
})
(此结果为List(x0$1, x1$1)
)
到
val paramVars = method.paramLists.flatMap(_.map { s =>
s.name
})
(此结果为List(x, y)
)