【发布时间】:2015-09-16 22:29:01
【问题描述】:
我正在尝试在宏中使用类型的字段,并将字段的符号或类型符号传递给方法,以便我可以执行一些需要有关该类型的具体信息的操作。
我有这样的代码(玩弄变体):
object Macros {
import scala.reflect.runtime.universe._
def foo(t: Symbol) : String = t.name.decoded
def materializeWriterImpl[T: c.WeakTypeTag](c: Context): c.Expr[List[String]] = {
import c.universe._
val tpe = weakTypeOf[T]
val fields = tpe.declarations.collectFirst {
case m: MethodSymbol if m.isPrimaryConstructor => m
}.get.paramss.head
c.Expr[List[String]] { q"""
val q = $fields
val names = q.map(Macros.foo)
List(names)
"""
}
}
}
我得到的错误是
Error:(53, 24) Can't unquote List[c.universe.Symbol], consider using .. or providing an implicit instance of Liftable[List[c.universe.Symbol]]
val names = foo($fields)
^
所以,也许不可能使用 qquotes 来提升符号/类型。但我可以在StandardLiftableApi 中看到执行此操作的方法:
implicit def liftScalaSymbol : U#Liftable[scala.Symbol]
implicit def liftType[T <: U#Type] : U#Liftable[T]
如果我传递字符串,我可以让它工作,就像测试一样,但我真的需要更实质性的东西传递出去。
【问题讨论】:
-
乍一看,我想说你想要的只是 q"List(..${fields.map(Macros.foo)})"。您在这里的主要概念错误是您试图生成映射符号的代码,而不是让您生成的代码映射符号然后提升结果。作为旁注,
liftScalaSymbol用于提升scala.Symbol,而不是Universe.Symbol。 -
此外,由于编译器在错误消息中提示,当您想要插入列表时,您需要在
$前面加上两个点 (..)。请参阅 quasiquotes 文档。 -
是的,我(在基本层面上)已经理解“..”了。您的第一条评论真的很有趣,我尝试将我的输出生成为 quasiquotes,然后包含 qqs 列表,但这也不起作用(同样的 Liftable 错误)。编写您赢得的 Liftable 实现是否通常?
-
但是你试过只返回
c.Expr[List[String]](q"List(..${fields.map(Macros.foo)})")吗?它有效吗?如果不是,那么确切的错误是什么?或者,如果您需要做的不仅仅是获取字段名称,它究竟是什么? -
我想递归生成一个模式,因此我需要获取字段名称和一些类型信息。所以理想情况下我想传递一个符号,或者一个名字+类型。
标签: scala macros scala-macros