Scala捕获表达式名称没有宏

use*_*883 1 macros scala

我试图在不使用宏的情况下获取表达式调用的名称.我有以下示例代码:

case class Person(name: String, age: Int)
case class MyClass[T]() {
    def doSomething(value: Any)
}
val p = Person("Bob",40)
val my = MyClass[Person]
my.doSomething(p.name)
my.doSomething(p.age)
Run Code Online (Sandbox Code Playgroud)

有没有方法中一个简单的方法doSomething来捕捉表情的名字进行调用时使用,例如捕获String的价值nameage

我知道,如果我转doSomething成一个宏传递的参数是ExprContext,我可以得到使用名称TreeExpr,但是给定宏的复杂性,我的那种东西,以避免在这种情况下,使用一个.

Ben*_*ich 5

最简洁的答案是不.除了宏之外,目前无法获得抽象语法树(AST).

你可以reify在这里使用一些成功,但这本身就是一个宏,这需要doSomething调用者必须使用reify,这很奇怪.例如,在以下代码中doSomething返回属性名称以及传递给case类构造函数的实例的属性值:

import scala.reflect.runtime.universe._
import scala.reflect.runtime._ 
import scala.tools.reflect.ToolBox

case class Person(name: String, age: Int)
case class MyClass[T](t: T) {
    val tb = currentMirror.mkToolBox()
    def doSomething[U](expr: Expr[T => U]) = Some(expr.tree) collect {
        case f@Function(_, Select(_, property)) => 
            val func = tb.eval(f).asInstanceOf[T => U]
            property.decoded -> func(t)
    }
}
Run Code Online (Sandbox Code Playgroud)

可以称之为:

val p = Person("Bob",40)
val my = MyClass(p)
//The caller needs to use reify, which is strange!
my.doSomething(reify((_:Person).name)) //Some(("name", "Bob"))
my.doSomething(reify { (p:Person) => p.age }) //Some(("age",40))
Run Code Online (Sandbox Code Playgroud)

但这很脆弱且容易出错,此时你不妨写一个宏!

您的另一个选择是传入String属性的名称并使用反射从实例中获取该属性.

您可以查看文档Treesmacros了解更多信息.