如何使用Scala宏生成“合格选择”?

时间:2014-07-27 12:15:59

标签: scala macros scala-macros scala-2.11

我正在玩Scala宏。在阅读示例时,我经常会看到这种模式:

Select(
  Select(
    Ident(TermName("scala")), 
    TermName("Some")
  ), 
  TermName("apply")
)

这是非常冗长和重复的。有没有办法更简洁地表达这一点?我正在寻找类似的东西:

select("scala.Some.apply")

2 个答案:

答案 0 :(得分:2)

不要注意评论者。 [编者按:干幽默警报。]

只有真正理智的人才会使用quasiquotes

Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0).
Type in expressions to have them evaluated.
Type :help for more information.

scala> q"scala.Some(42)"
res0: reflect.runtime.universe.Tree = scala.Some(42)

scala> showRaw(res0)
res1: String = Apply(Select(Ident(TermName("scala")), TermName("Some")), List(Literal(Constant(42))))

scala> showRaw(q"scala.Some.apply")
res2: String = Select(Select(Ident(TermName("scala")), TermName("Some")), TermName("apply"))

scala> showRaw(q"scala.Some")
res3: String = Select(Ident(TermName("scala")), TermName("Some"))

scala> showRaw(tq"scala.Some")
res4: String = Select(Ident(TermName("scala")), TypeName("Some"))

通常,您使用qq来记录非常复杂的表达式:

// tq"scala.Some"
val t = Select(Ident(TermName("scala")), TypeName("Some"))

答案 1 :(得分:0)

解决这个问题的一个简单方法是实现以下功能:

def select(identifier : String) : Tree = {
  val terms = identifier.split("\\.").map { TermName(_) }
  terms.tail.foldLeft[Tree](Ident(terms.head)) { Select(_, _) }
}

REPL的示例输出:

scala> select("scala")
res0: Tree = Ident(TermName(scala))

scala> select("scala.Some")
res1: Tree = Select(Ident(TermName(scala)),TermName(Some))

scala> select("scala.Some.apply")
res2: Tree = Select(Select(Ident(TermName(scala)),TermName(Some)),TermName(apply))

现在,我不知道这是否会以某种方式阻止某些编译器优化,如果明确写出AST,可能会执行其他优化......