我试图在不使用宏的情况下获取表达式调用的名称.我有以下示例代码:
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的价值name和age?
我知道,如果我转doSomething成一个宏传递的参数是Expr的Context,我可以得到使用名称Tree的Expr,但是给定宏的复杂性,我的那种东西,以避免在这种情况下,使用一个.
最简洁的答案是不.除了宏之外,目前无法获得抽象语法树(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属性的名称并使用反射从实例中获取该属性.