来自Expr的scala宏提取值

时间:2014-01-22 17:39:05

标签: scala scala-macros

我有下一个代码:

object TestMacro {

  def test[A](vval: List[A]) = macro testImpl[A]

  def testImpltestImpl[A: c.WeakTypeTag](c: Context)(vval: c.Expr[List[A]]) = {
    import c.universe._

    println(vval) // =>  Expr[Nothing](immutable.this.List.apply[Int](1, 2, 3))

    reify{} 
  }
}

示例:

test(List(1,2,3))

如何从List[Int]获取真实类型Expr并获取宏中具有(1,2,3)值的List实例?

1 个答案:

答案 0 :(得分:2)

您可以使用方法showRaw获取Tree结构,如下所示:

import reflect.runtime.universe._
showRaw{ reify{ List(1, 2, 3) } }
// Expr(Apply(Select(Ident(scala.collection.immutable.List), newTermName("apply")), List(Literal(Constant(1)), Literal(Constant(2)), Literal(Constant(3)))))

reify返回Expr

缩进的结果:

Expr(
  Apply(
    Select(
      Ident(scala.collection.immutable.List),
      newTermName("apply")
    ),
    List(
      Literal(Constant(1)),
      Literal(Constant(2)),
      Literal(Constant(3))
    )
  )
)

所以你可以解构这棵树:

val vval = reify{ List(1, 2, 3) }
val l =
  vval.tree match {
    case Apply(_, l) => l
  }
// List[reflect.runtime.universe.Tree] = List(1, 2, 3)


val ints =
  l map {
    case Literal(Constant(i: Int)) => i
  }
// List[Int] = List(1, 2, 3)

请注意,只有当您的方法test被调用为test(List(1, 2, 3))时,它才会起作用。它将在val l = List(1, 2, 3); test(l)失败。它甚至会在test(List(1+1))上失败。

此类参数提取的唯一有用应用是基于宏的字符串插值like this