使用Scala宏我希望能够访问函数f的源代码。
以下是我的问题的简化示例:
def logFImplementation(f: => Boolean) {
val sourceCodeOfF: String = ... // <-- how to get source code of f??
println("Scala source of f=" + sourceCodeOfF)
}
所以:
logFImplementation { val i = 5; List(1, 2, 3); true }
它应该打印:
Scala source of f=val i: Int = 5; immutable.this.List.apply[Int](1, 2, 3); true
(现在我测试了Macro to access source code text at runtime,它适用于{ val i = 5; List(1, 2, 3); true }.logValueImpl
,但对于f.logValueImpl
,它只打印f
。)
感谢您的任何建议。
答案 0 :(得分:4)
这可能是“线索坏死”,因为这个问题很古老。我不得不努力解决这个问题。
import scala.reflect.macros.blackbox.Context
import scala.language.experimental.macros
object FunctionWrapper {
implicit def apply[P, R](fn: P => R): FunctionWrapper[P, R] = macro apply_impl[P, R]
def apply_impl[P: c.WeakTypeTag, R: c.WeakTypeTag](c: Context)(fn: c.Expr[P => R]):
c.Expr[FunctionWrapper[P, R]] = {
import c.universe._
c.Expr(q" new FunctionWrapper($fn, ${show(fn.tree))})")
}
}
class FunctionWrapper[P, R](val fn: P => R, description: String)
extends Function1[P, R] {
def apply(p: P) = fn(p)
override def toString = description
}
使用它的一个例子(必须在一个单独的编译模块中)是:
object FunctionWrapperUser {
def main(args: Array[String]): Unit = {
val double = FunctionWrapper((i: Int) => i * 2)
println(s"double to String is $double")
println(double(4))
}
}
答案 1 :(得分:2)
我严重怀疑是否有可能。
首先,宏是编译时的东西。他们所做的只是转换程序所包含的抽象语法树。这正是你能够做{ val i = 5; List(1, 2, 3); true }.logValueImpl
的原因:AST就在这里,所以将它打印成字符串没有困难。但宏只是无法解析运行时值,因为在运行时有 no 宏。
其次,绝对没有理由相信f
是Scala代码。我可以像这样从Java调用你的函数(不确定我的名字是否正确,但是这个想法仍然是相同的):
someObject.logFImplementation(new scala.Function0<Boolean>() {
@Override
public Boolean apply() {
// do some things in Java
}
});
(这是可能的,因为内部按名称调用参数转换为scala.Function0
个对象)。在这种情况下,您希望您的功能打印什么?