0

我正在学习如何编写 Scala 宏并编写了一个宏注释,该注释从带注释的函数的类型参数中删除了注释。这里是。

要删除的注释

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, privateWithin, 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)and进行了比较println(expandees)

List(def someMethod[@new garbage() Source, G[_]](i: Int): G[List[Int]])
List(def someMethod[Source, G[_]](i: Int): G[List[Int]])

关于解决方案的问题是它看起来很难阅读。也许我没有充分发挥准引号的潜力。有没有办法简化宏实现(可能更广泛地使用准引号......)?

4

1 回答 1

2

宏代码难以阅读是可以的 :) 这就是为什么元编程不应该成为工具#1 的原因。

我看不出如何显着减少您的代码。

你可以更换

val modifiedMods = mods match {
  case Modifiers(flags, privateWithin, annots) =>
    Modifiers(flags, privateWithin, annots.filter(_ == q"new garbage()"))
}

单线

val modifiedMods = mods.mapAnnotations(_.filter(_ == q"new garbage()"))

如果您在许多宏中继续执行相同的转换集,您可以类似地定义辅助方法,例如mapDefmapTypeParams...

如果 quasiquotes 变得太麻烦,您可以考虑使用ClassDef, Template, DefDef... 代替 quasiquotes 或在方便时将它们与 quasiquotes 混合使用。

(这些问题通常是针对https://codereview.stackexchange.com/的,尽管元编程在那里似乎 那么流行。)

于 2020-10-30T23:22:53.103 回答