scala 2.10.2调用';宏方法&x27;泛型类型无效

scala 2.10.2调用';宏方法&x27;泛型类型无效,scala,generics,scala-macros,Scala,Generics,Scala Macros,我定义以下宏来将案例字段转换为映射 import scala.language.experimental.macros import scala.reflect.macros.Context def asMap_impl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]) = { import c.universe._ val mapApply = Select(reify(Map).tree, newTerm

我定义以下宏来将案例字段转换为映射

   import scala.language.experimental.macros
    import scala.reflect.macros.Context

    def asMap_impl[T: c.WeakTypeTag](c: Context)(t: c.Expr[T]) = {
      import c.universe._

      val mapApply = Select(reify(Map).tree, newTermName("apply"))

      val pairs = weakTypeOf[T].declarations.collect {
        case m: MethodSymbol if m.isCaseAccessor =>
          val name = c.literal(m.name.decoded)
          val value = c.Expr(Select(t.tree, m.name))
          reify(name.splice -> value.splice).tree
      }

      c.Expr[Map[String, Any]](Apply(mapApply, pairs.toList))
    }
以及该方法的实现

def asMap[T](t: T) = macro asMap_impl[T]
然后我定义一个case类来测试它

case class User(name : String)
它工作正常(使用scala repl):

但是当我用另一个通用方法包装此方法时

def printlnMap[T](t: T) = println(asMap(t))
此方法始终打印空地图:

scala> printlnMap(User("foo"))
Map()

类型信息似乎丢失了,如何让printlnMap打印所有字段?

这不起作用的原因是,在编译
printlnMap
函数时,只调用一次宏。这样,它将
T
视为一个抽象类型。不会在每次调用
printlnMap
时调用宏

快速解决此问题的一种方法是将
printlnMap
也作为宏实现。当然,这并不理想。因此,这里有一种不同的方法-类型类实例的物化:

首先,定义一个typeclass,它允许我们将case类实例转换为映射:

trait CaseClassToMap[T] {
  def asMap(t: T): Map[String,Any]
}
然后,实现一个宏,该宏将具体化某个案例类的此类实例
T
。您可以将它放入
CaseClassToMap
companion对象中,使其全局可见

object CaseClassToMap {
  implicit def materializeCaseClassToMap[T]: CaseClassToMap[T] = macro impl[T]

  def impl[T: c.WeakTypeTag](c: Context): c.Expr[CaseClassToMap[T]] = {
    import c.universe._

    val mapApply = Select(reify(Map).tree, newTermName("apply"))

    val pairs = weakTypeOf[T].declarations.collect {
      case m: MethodSymbol if m.isCaseAccessor =>
        val name = c.literal(m.name.decoded)
        val value = c.Expr(Select(Ident(newTermName("t")), m.name))
        reify(name.splice -> value.splice).tree
      }

    val mapExpr = c.Expr[Map[String, Any]](Apply(mapApply, pairs.toList))

    reify {
      new CaseClassToMap[T] {
        def asMap(t: T) = mapExpr.splice
      }
    }
  }
}
现在,您可以执行以下操作:

def asMap[T: CaseClassToMap](t: T) =
  implicitly[CaseClassToMap[T]].asMap(t)

def printlnMap[T: CaseClassToMap](t: T) =
  println(asMap(t))

高级的怎么样?printMap[B,A[B]](A:A[B])=println(asMap(A)),它不编译。你能帮我处理更高级的类吗type@jilen在您的示例中没有使用更高级的类型。如果这是你的意思,那么这个方法对于带有类型参数的case类应该可以很好地工作。我想定义一个函数def call[R,a[R]@jilen你不是说
def call[R,a]
def asMap[T: CaseClassToMap](t: T) =
  implicitly[CaseClassToMap[T]].asMap(t)

def printlnMap[T: CaseClassToMap](t: T) =
  println(asMap(t))