Scala宏类型或符号解除 [英] Scala macros Type or Symbol lifted

查看:93
本文介绍了Scala宏类型或符号解除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在宏中使用类型的字段,并将字段的符号或类型ig传递给方法,以便我可以执行一些需要有关该类型的具体信息的操作.

I'm trying to use the fields of a type in a macro, and pass the symbol or typesigs for the fields to a method so I can do some operations that require concrete information about the type.

我有这样的代码(玩过各种游戏):

I have code like this (played about with variations):

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) ^

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中看到执行此操作的方法:

So, perhaps its not possible to lift symbol / type using qquotes. But I can see methods to do this in StandardLiftableApi:

implicit def liftScalaSymbol : U#Liftable[scala.Symbol]
implicit def liftType[T <: U#Type] : U#Liftable[T]

如果通过字符串作为测试,我可以使它正常工作,但是我确实需要更重要的东西.

I can get this working if I pass strings, just as a test, but I really need something more substantial passed out.

推荐答案

下面是关于您实际要实现的目标的评论,下面是一个相当全面的示例,显示了如何生成模式(对于完全组成的模式描述语言).

Following your comments about what you're actually trying to achieve, here's a rather comprehensive example that shows how to generate schemas (for a totally made up schema description language).

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}

这篇关于Scala宏类型或符号解除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆