scala 2.10.2调用泛型类型的"宏方法"不起作用

 杨barkema_252 发布于 2023-02-08 12:19

我定义了以下宏来将case字段转换为map

   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 class User(name : String)

它工作正常(使用scala repl):

 scala> asMap(User("foo")) res0:
 scala.collection.immutable.Map[String,String] = Map(name -> foo)

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

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

此方法始终打印空地图:

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

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

1 个回答
  • 这不起作用的原因是你的宏只会被调用一次 - 编译printlnMap函数时.这样它将被T视为抽象类型.每次调用时都不会调用宏printlnMap.

    快速解决此问题的一种方法是同时实现printlnMap宏.当然,这并不理想.所以,这是一个不同的方法 - 类型类实例的实现:

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

    trait CaseClassToMap[T] {
      def asMap(t: T): Map[String,Any]
    }
    

    然后,实现一个宏,将兑现这一类型的类的实例,对于一些案例类T.您可以将其放入CaseClassToMap伴随对象中,以便全局可见.

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

    2023-02-08 12:21 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有