Scala 2.10MethodSymbol
でaをメソッド定義ツリーの左側(つまり、 )に変える便利な方法はありますか?DefDef
たとえば、トレイトのインスタンスを取得し、そのトレイトのすべてのメソッドをいくつかのデバッグ機能でラップするマクロを作成するとします。私は次のように書くことができます:
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, ...)
これは、煩わしく、冗長で、エラーが発生しやすいものです。新しいReflectionAPIでこれを行うためのより良い方法がありませんか?