我正在评估创建宏注释的可能性和努力来解决这个问题:
@txn class Foo(var bar: Int)
进入这个:
import concurrent.stm.{Ref, InTxn}
class Foo(bar0: Int) {
private val _bar = Ref(bar0)
def bar(implicit tx: InTxn): Int = _bar()
def bar_=(value: Int)(implicit tx: InTxn): Unit = _bar() = value
}
(或者可能使用Foo
方法创建apply
个随播广告对象,目前还不确定)
现在我从ClassDef
身体看到的是这样的
List(<paramaccessor> var bar: Int = _,
def <init>(bar: Int) = {
super.<init>();
()
})
因此bar
显示为没有init(_
)的param-accessor,也是<init>
方法的参数。
我如何重写那个身体?
import scala.reflect.macros.Context
import scala.language.experimental.macros
import scala.annotation.StaticAnnotation
class txn extends StaticAnnotation {
def macroTransform(annottees: Any*) = macro txnMacro.impl
}
object txnMacro {
def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
val inputs = annottees.map(_.tree).toList
def reportInvalidAnnotationTarget(): Unit =
c.error(c.enclosingPosition,
"This annotation can only be used on a class definition")
val expandees: List[Tree] = inputs match {
case cd @ ClassDef(mods, nme, tp, tmp @ Template(parents, self, body)) :: Nil =>
println(s"Body: $body")
???
case _ =>
reportInvalidAnnotationTarget()
inputs
}
val outputs = expandees
c.Expr[Any](Block(outputs, Literal(Constant(()))))
}
}
答案 0 :(得分:2)
正如尤金所说,使用quasiquotes可以使这更容易。我还没有提供完整的解决方案,但我尝试了一些部分,所以我认为这些方面的内容可行:
case q"class $name extends $parent with ..$traits { ..$body }"=>
val newBody = body.flatMap {
case q"var $varName = $varBody" =>
List(
//put the three defs you need here. some variant of this ...
q"""private val ${stringToTermName("_" + varName.toString)} = Ref(${stringToTermName(varName.name + "0")})""",
//etc ...
)
case other => other
}
q"class $name extends $parent with ..$ttraits { ..${(newBody).toList} }"
您可能会发现我的博文相关:http://imranrashid.com/posts/learning-scala-macros/
您可能还会发现这对定义吸气剂和放大器非常有用。 setter方法: https://groups.google.com/forum/#!searchin/scala-user/macro|sort:date/scala-user/Ug75FW73mJI/F1ijU0uxZAUJ