Есть ли удобный способ превратить _ 1_ в левую часть дерева определения метода (т. Е. _ 2_) в Scala 2.10?
Например, предположим, что я хочу создать макрос, который будет принимать экземпляр признака и обертывать все методы этого признака некоторыми функциями отладки. Я могу написать следующее:
import scala.language.experimental.macros
import scala.reflect.macros.Context
object WrapperExample {
def wrap[A](a: A): A = macro wrap_impl[A]
def wrap_impl[A: c.WeakTypeTag](c: Context)(a: c.Expr[A]) = {
import c.universe._
val wrapped = weakTypeOf[A]
val f = Select(reify(Predef).tree, "println")
val methods = wrapped.declarations.collect {
case m: MethodSymbol if !m.isConstructor => DefDef(
Modifiers(Flag.OVERRIDE),
m.name,
Nil, Nil,
TypeTree(),
Block(
Apply(f, c.literal("Calling: " + m.name.decoded).tree :: Nil),
Select(a.tree, m.name)
)
)
}.toList
//...
}
Я избавился от утомительной работы по встраиванию этих методов в новый анонимный класс, который реализует эту черту, а затем создает экземпляр этого класса - вы можете найти полный рабочий пример здесь, если вам интересно.
Теперь я могу написать это, например:
scala> trait X { def foo = 1; def bar = 'a }
defined trait X
scala> val x = new X {}
x: X = $anon$1@15dd533
scala> val w: X = WrapperExample.wrap[X](x)
w: X = $1$$1@27c3a4a3
scala> w.foo
Calling: foo
res0: Int = 1
scala> w.bar
Calling: bar
res1: Symbol = 'a
Так что это работает, но только в очень простых случаях - не будет, если у трейта есть методы со списками параметров, с модификаторами доступа, аннотациями и т. Д.
Что мне действительно нужно, так это функция, которая примет символ метода и дерево для нового тела и вернет DefDef
. Я начал писать один от руки, но он включает в себя множество неудобных вещей вроде этого:
List(if (method.isImplicit) Some(Flag.IMPLICIT) else None, ...)
Это раздражает, многословно и подвержено ошибкам. Не хватает ли мне более удобного способа сделать это в новом API отражения?