在运行时访问函数源代码的宏

Art*_*nek 5 reflection macros scala scala-macros

使用 Scala 宏,我想访问函数 f 的源代码。

这是我的问题的简化示例:

def logFImplementation(f: => Boolean) {
    val sourceCodeOfF: String = ... // <-- how to get source code of f??

    println("Scala source of f=" + sourceCodeOfF)
}
Run Code Online (Sandbox Code Playgroud)

因此对于:

logFImplementation { val i = 5; List(1, 2, 3); true }
Run Code Online (Sandbox Code Playgroud)

它应该打印:

Scala source of f=val i: Int = 5; immutable.this.List.apply[Int](1, 2, 3); true
Run Code Online (Sandbox Code Playgroud)

(现在我测试了宏以在运行时访问源代码文本,它非常有用,{ val i = 5; List(1, 2, 3); true }.logValueImplf.logValueImpl它只是打印f.)

感谢您的任何建议。

Sta*_*ura 5

这可能是“线程死灵术”,因为这个问题已经很老了。我不得不努力解决这个问题。

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
}
Run Code Online (Sandbox Code Playgroud)

它的使用示例(必须位于单独的编译模块中)是:

 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))
  }
}
Run Code Online (Sandbox Code Playgroud)


Vla*_*eev 2

严重怀疑这是可能的。

首先,宏是编译时的东西。他们所做的只是转换你的程序组成的抽象语法树。这正是您能够这样做的原因{ val i = 5; List(1, 2, 3); true }.logValueImpl:AST 就在这里,因此将其打印为字符串没有任何困难。但宏无法解析运行时值,因为运行时没有宏。

其次,绝对没有理由相信这f是 Scala 代码。我可以像这样从 Java 调用你的函数(不确定我的所有名称是否正确,但想法仍然相同):

someObject.logFImplementation(new scala.Function0<Boolean>() {
    @Override
    public Boolean apply() {
        // do some things in Java
    }
});
Run Code Online (Sandbox Code Playgroud)

(这是可能的,因为内部按名称调用参数被转换为scala.Function0对象)。在这种情况下,您希望您的函数打印什么?