我正在尝试在宏中使用某个类型的字段,并将字段的符号或typesigs传递给方法,以便我可以执行一些操作,这些操作需要有关该类型的具体信息。
我有这样的代码(与变体一起玩):
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]
如果我传递字符串,我可以使用它,就像测试一样,但我真的需要更大量的传递。
答案 0 :(得分:1)
根据您对实际尝试实现的内容的评论,这是一个相当全面的示例,展示了如何生成模式(对于完全构建的模式描述语言)。
import scala.language.experimental.macros
import scala.reflect.macros._
implicit class Schema[T](val value: String) extends AnyVal {
override def toString = value
}; object Schema {
implicit val intSchema: Schema[Int] = "int"
implicit val floatSchema: Schema[Float] = "float"
implicit val stringSchema: Schema[String] = "string"
// ... and so on for all the base types you need to support
implicit def optionSchema[T:Schema]: Schema[Option[T]] = "optional[" + implicitly[Schema[T]] + "]"
implicit def listSchema[T:Schema]: Schema[List[T]] = "list_of[" + implicitly[Schema[T]] + "]"
implicit def classSchema[T]: Schema[T] = macro classSchema_impl[T]
def classSchema_impl[T:c.WeakTypeTag](c: Context): c.Expr[Schema[T]] = {
import c.universe._
val T = weakTypeOf[T]
val fields = T.declarations.collectFirst {
case m: MethodSymbol if m.isPrimaryConstructor => m
}.get.paramss.head
val fieldSchemaPartTrees: Seq[Tree] = fields.map{ f =>
q"""${f.name.decoded} + ": " + implicitly[Schema[${f.typeSignature}]]"""
}
c.Expr[Schema[T]](q"""
new Schema[$T](
"{" +
Seq(..$fieldSchemaPartTrees).mkString(", ") +
"}"
)
""")
}
}
还有一些REPL测试:
scala> case class Foo(ab: Option[String], cd: Int)
defined class Foo
scala> case class Bar(ef: List[Foo], gh: Float)
defined class Bar
scala> implicitly[Schema[Bar]]
res7: Schema[Bar] = {ef: list_of[{ab: optional[string], cd: int}], gh: float}