将一个方法调用插入到许多其他方法中

时间:2013-11-14 10:26:21

标签: scala

我需要为应用程序中的其他方法添加方法。它们中有很多。有没有明智的方法可以做到这一点,除了直截了当的方法 - 手动将方法调用插入每个方法?

1 个答案:

答案 0 :(得分:4)

def macros的实施,请参见this answer

使用macro annotations实施:

import scala.reflect.macros.Context
import scala.language.experimental.macros

def wrappedImpl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
  import c.universe._
  import scala.reflect.internal.Flags._

  object DefMods{
    def unapply(mods: Modifiers): Option[Modifiers] = {
      val fs = mods.flags.asInstanceOf[Long]
      if ((fs & DEFERRED) == 0 && (fs & STABLE) == 0) Some(mods)
      else None
    }
  }

  def wrap(t: Tree) = t match {
    case DefDef(DefMods(mods), name, tparams, vparams, tpt, body) if name != nme.CONSTRUCTOR =>
      DefDef(mods, name, tparams, vparams, tpt,
             q"""
               println("before")
               val res = $body
               println("after")
               res""")
    case x => x
  }

  def transform(t: Tree) = t match {
    case ClassDef(mods, name, tparams, Template(parents, self, methods)) =>
      ClassDef(mods, name, tparams, Template(parents, self, methods.map{wrap(_)}))
    case x => x
  }

  c.Expr[Any](Block(annottees.map(_.tree).map(transform(_)).toList, Literal(Constant(()))))
}

import scala.annotation.StaticAnnotation
class wrapped extends StaticAnnotation {
  def macroTransform(annottees: Any*) = macro wrappedImpl
}

您必须使用compiler plugin进行quasiquotes。

用法:

@wrapped class Test {
  def test() = println("test")
}

scala> new Test().test()
before
test
after