问题描述
我正在学习如何编写Scala宏并编写了宏注释,该宏注释从带注释的函数的类型参数中删除了注释。在这里。
要删除的注释:
FileUploadSerializer
用于删除注释的宏的实现:
class garbage extends StaticAnnotation
测试方法:
@compileTimeOnly("Compile-time only annotation")
class removeGarbage extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro impl
}
object removeGarbage {
def impl(c: whiteBox.Context)(annottees: c.Tree*) = {
import c.universe._
println(annottees)
val expandee = annottees.toList collect {
case q"$mods def $templatename[..$typeparams](...$paramss): $tpt = $body" =>
val modifiedParams = typeparams collect {
case q"$mods type $name[..$args] = $tpt" =>
val modifiedMods = mods match {
case Modifiers(flags,privateWithin,annots) =>
Modifiers(flags,annots.filter(_ == q"new garbage()"))
}
q"$modifiedMods type $name[..$args] = $tpt"
}
q"$mods def $templatename[..$modifiedParams](...$paramss): $tpt = $body"
case annottee =>
c.abort(c.enclosingPosition,s"$annottee cannot be annotated with @removeGarbage. Only def methods are allowed")
}
println(expandee)
q"..$expandee"
}
}
这似乎很好。为了进行检查,我将添加的日志与trait Test{
@removeGarbage
def someMethod[@garbage Source,G[_]](i: Int): G[List[Int]]
}
和println(annottees)
进行了比较:
println(expandees)
解决方案的问题 是它似乎很难阅读。也许我没有充分利用准报价。有没有一种方法可以简化宏的实现(可能更广泛地使用准引用...)?
解决方法
没关系让宏代码难以阅读:) 这就是为什么元编程不应该成为工具#1的原因。
我看不到如何大幅减少您的代码。
您可以替换
val modifiedMods = mods match {
case Modifiers(flags,privateWithin,annots) =>
Modifiers(flags,annots.filter(_ == q"new garbage()"))
}
单线
val modifiedMods = mods.mapAnnotations(_.filter(_ == q"new garbage()"))
如果您在许多宏中继续进行相同的转换,则可以类似地定义辅助方法,例如mapDef
,mapTypeParams
...
如果准引号变得过于繁琐,您can consider可以使用ClassDef
,Template
,DefDef
...代替准引号,或在方便时将它们与准引号混合。 >
(这些问题通常是针对https://codereview.stackexchange.com/的,尽管元编程似乎在not so中很流行。)