2013-03-10 109 views
2

我有兩個嵌套的case類:轉換巢式病例類嵌套地圖斯卡拉

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

,我想轉換爲Map類型的嵌套地圖[字符串,任何]讓我得到這樣的:

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

當然,解決方案應該是通用的,適用於任何案例類。

注意: This discussion給出瞭如何將單個案例類映射到Map的很好的答案。但我無法適應嵌套的案例類。相反,我得到:

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

這個問題不是很清楚。 Map中的「myInt」和「myInner」是什麼?它們是從'OuterClass'實例中獲取的,還是它被用作鍵的'String'?無論如何,使用'Any'表示你可能在像Scala這樣的靜態類型語言中做錯了什麼。澄清你想要做什麼,你會得到一些有用的建議。 – 2013-03-10 17:04:32

+0

檢查'productIterator',這是一種遍歷'Product's的所有值的方法。所有案例分類都是「產品」。 – pedrofurla 2013-03-10 18:13:08

+0

@ luigi-plinge不知道我是否正確回答你的問題。在Map的上下文中,myInt和myInner都來自OuterClass實例,並用作鍵。這是爲了通用。 爲了闡明背景,我在我的應用程序中爲主對象使用了嵌套的大小寫類。此外,我有[Bencode](https://en.wikipedia.org/wiki/Bencode)[編碼器](https://github.com/pyronicide/scala-bencode/blob/master/src/main/scala/ org/saunter/bencode/Bencode.scala#L105),它接受字符串,Ints和地圖。我的目的是將我的對象轉換爲嵌套地圖並將其提供給Bencode編碼器 – jans 2013-03-10 23:52:18

回答

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

由於路易吉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中的運行時反射 - 它幾乎是不必要的。我只發佈這個答案,因爲如果你確定必須使用運行時反射,最好使用Scala Reflection API而不是Java。

+0

爲什麼不使用'productIterator'? – pedrofurla 2013-03-10 18:12:17

+0

@pedrofurla:因爲我想假裝'productIterator'不存在?當你使用'scala.reflect.runtime'時,至少很明顯你正在做一件令人討厭的事情。 – 2013-03-10 20:18:31