2014-01-22 1 views
0

У меня есть следующий код:макро значение Scala экстракта из Expr

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) значений в макросе?

ответ

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.

+0

Возможно ли во время компиляции? – lito

+0

@lito: да, я даже создал 'val vval', как в вашем коде, чтобы вы скопировали' val l = ...; val ints = ... 'к вашему методу. – senia