scala macro извлекает значения из Expr

100
14

У меня есть следующий код:

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 и получить экземпляр List с (1,2,3) значениями в макросе?

спросил(а) 2021-01-25T14:59:36+03:00 5 месяцев назад
1
Решение
77

Вы можете использовать метод 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) val l = List(1, 2, 3); test(l). Это не сработает даже при test(List(1+1)).

Единственное полезное приложение для извлечения таких параметров макросов на основе строки интерполяции, как это.

ответил(а) 2021-01-25T14:59:36+03:00 5 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема