2

2 つの入れ子になったケース クラスがあります。

case class InnerClass(param1: String, param2: String)
case class OuterClass(myInt: Int, myInner: InnerClass)
val x = OuterClass(11, InnerClass("hello", "world"))

タイプ Map[String,Any] のネストされたマップに変換して、次のようなものを取得したい:

Map(myInt -> 11, myInner -> Map(param1 -> hello, param2 -> world))

もちろん、ソリューションは汎用的で、どのケース クラスでも機能する必要があります。

注: このディスカッションでは、単一のケース クラスをマップにマップする方法について適切な回答が得られました。しかし、ネストされたケース クラスに適応させることはできませんでした。代わりに私は得る:

Map(myInt -> 11, myInner -> InnerClass(hello,world)
4

3 に答える 3

2

上記のコメントで Luigi Plinge が指摘しているように、これは非常に悪い考えです。型の安全性を窓の外に放り出し、多くの醜いキャストや実行時エラーで立ち往生することになります。

そうは言っても、新しいScala 2.10 Reflection API を使用すると、やりたいことを簡単に実行できます。

def anyToMap[A: scala.reflect.runtime.universe.TypeTag](a: A) = {
  import scala.reflect.runtime.universe._

  val mirror = runtimeMirror(a.getClass.getClassLoader)

  def a2m(x: Any, t: Type): Any = {
    val xm = mirror reflect x

    val members = t.declarations.collect {
      case acc: MethodSymbol if acc.isCaseAccessor =>
        acc.name.decoded -> a2m((xm reflectMethod acc)(), acc.typeSignature)
    }.toMap

    if (members.isEmpty) x else members
  }

  a2m(a, typeOf[A])
}

その後:

scala> println(anyToMap(x))
Map(myInt -> 11, myInner -> Map(param1 -> hello, param2 -> world))

ただし、これは行わないでください。実際、Scala ではランタイム リフレクションを完全に回避するために最善を尽くす必要があります。ランタイム リフレクションを使用する必要があると判断した場合は、Java よりも Scala Reflection API を使用する方がよいため、この回答を投稿するだけです。

于 2013-03-10T17:40:45.900 に答える
0

再帰的に呼び出すだけです。そう

def getCCParams(cc: AnyRef) =
  (Map[String, Any]() /: cc.getClass.getDeclaredFields) {(a, f) =>
    f.setAccessible(true)
    val value = f.get(cc) match {
      // this covers tuples as well as case classes, so there may be a more specific way
      case caseClassInstance: Product => getCCParams(caseClassInstance)
      case x => x
    }
    a + (f.getName -> value)
  }
于 2013-03-10T17:33:00.727 に答える