案例类在Scala中映射

有谁知道,如果有一个很好的方式,我可以转换一个Scala案例类实例,例如

case class MyClass(param1: String, param2: String)
val x = MyClass("hello", "world")

进入某种映射,例如

getCCParams(x) returns "param1" -> "hi", "param2" -> "3"

它适用于任何案例类,而不仅仅是预定义类。 我发现你可以通过编写一个询问底层产品类的方法来拉出案例类名称,例如

def getCCName(caseobj: Product) = caseobj.productPrefix 
getCCName(x) returns "MyClass"

所以我正在寻找一个类似的解决方案,但案例类字段。 我可以想象一个解决方案可能需要使用Java反射,但如果底层的案例类实现发生变化,我不愿意写一些可能会在未来的Scala版本中崩溃的东西。

目前我正在开发Scala服务器,并使用案例类定义协议及其所有消息和异常,因为它们是如此美丽,简洁的构造。 但是,我需要将它们翻译成Java地图,以便通过消息传递层为任何客户端实现使用。 我目前的实现只是分别为每个案例类定义一个翻译,但是找到一个通用的解决方案会很好。


这应该工作:

def getCCParams(cc: AnyRef) =
  (Map[String, Any]() /: cc.getClass.getDeclaredFields) {(a, f) =>
    f.setAccessible(true)
    a + (f.getName -> f.get(cc))
  }

因为case类扩展Product可以简单地使用.productIterator来获取字段值:

def getCCParams(cc: Product) = cc.getClass.getDeclaredFields.map( _.getName ) // all field names
                .zip( cc.productIterator.to ).toMap // zipped with all values

或者:

def getCCParams(cc: Product) = {          
      val values = cc.productIterator
      cc.getClass.getDeclaredFields.map( _.getName -> values.next ).toMap
}

Product的一个优点是你不需要在字段上调用setAccessible来读取它的值。 另一个是productIterator不使用反射。

请注意,此示例适用于不扩展其他类并且不在构造函数外部声明字段的简单案例类。


如果有人寻找递归版本,这里是@ Andrejs解决方案的修改:

def getCCParams(cc: Product): Map[String, Any] = {
  val values = cc.productIterator
  cc.getClass.getDeclaredFields.map {
    _.getName -> (values.next() match {
      case p: Product if p.productArity > 0 => getCCParams(p)
      case x => x
    })
  }.toMap
}

它还将嵌套的case-classes扩展为嵌套级别的地图。

链接地址: http://www.djcxy.com/p/68261.html

上一篇: Case class to map in Scala

下一篇: When do you use Java's @Override annotation and why?