Scala Nested HashMaps,如何访问 Case Class 值属性?

Scala Nested HashMaps, how to access Case Class value properties?

Scala新手,继续纠结Option相关代码。我有一个由 Case Class 实例构建的 HashMap,它们本身包含具有 Case Class 实例值的哈希映射。我不清楚如何访问检索到的 Class 个实例的属性:

import collection.mutable.HashMap

case class InnerClass(name: String, age: Int)
case class OuterClass(name: String, nestedMap: HashMap[String, InnerClass])

// Load some data...hash maps are mutable
val innerMap = new HashMap[String, InnerClass]()
innerMap += ("aaa" -> InnerClass("xyz", 0))

val outerMap = new HashMap[String, OuterClass]()
outerMap += ("AAA" -> OuterClass("XYZ", innerMap))

// Try to retrieve data
val outerMapTest = outerMap.getOrElse("AAA", None)
val nestedMap = outerMapTest.nestedMap

这会产生 error: value nestedMap is not a member of Option[ScalaFiddle.OuterClass]

// Try to retrieve data a different way
val outerMapTest = outerMap.getOrElse("AAA", None)
val nestedMap = outerMapTest.nestedMap

这会产生 error: value nestedMap is not a member of Product with Serializable

请告知我将如何访问 outerMapTest.nestedMap。我最终还需要从 nestedMap HashMap 中获取值和属性。

你想要

val maybeInner = outerMap.get("AAA").flatMap(_.nestedMap.get("aaa"))
val maybeName = maybeInner.map(_.name)

如果你喜欢冒险,你可以得到

val name: String = maybeName.get

但如果它不存在,那将引发错误。如果它是 None

您可以使用以下表达式访问 nestMap。

scala> outerMap.get("AAA").map(_.nestedMap).getOrElse(HashMap())
res5: scala.collection.mutable.HashMap[String,InnerClass] = Map(aaa -> InnerClass(xyz,0))

如果 "AAA" 不存在于 outerMap Map 对象中,那么下面的表达式将返回一个空的 HashMap,如 .getOrElse 方法参数 (HashMap()) 中所示。

由于您使用的是 .getOrElse("someKey", None),returns 您的类型是 Product(不是您期望的实际类型 OuterClass

scala> val outerMapTest = outerMap.getOrElse("AAA", None)
outerMapTest: Product with Serializable = OuterClass(XYZ,Map(aaa -> InnerClass(xyz,0)))

所以 Product 需要进行模式匹配或转换为 OuterClass

模式匹配示例

scala> outerMapTest match { case x : OuterClass => println(x.nestedMap); case _ => println("is not outerclass") }
Map(aaa -> InnerClass(xyz,0))

当 outerMapTest 为 None 时,转换示例是一个糟糕的想法(模式匹配优于转换)

scala> outerMapTest.asInstanceOf[OuterClass].nestedMap
res30: scala.collection.mutable.HashMap[String,InnerClass] = Map(aaa -> InnerClass(xyz,0))

但更好的解决方法是简单地使用 .get,它非常聪明,可以给你 Option[OuterClass]

scala> outerMap.get("AAA").map(outerClass => outerClass.nestedMap)
res27: Option[scala.collection.mutable.HashMap[String,InnerClass]] = Some(Map(aaa -> InnerClass(xyz,0)))

对于不存在的密钥,给你 None

scala> outerMap.get("I dont exist").map(outerClass => outerClass.nestedMap)
res28: Option[scala.collection.mutable.HashMap[String,InnerClass]] = None

您可以采取一些步骤来深入了解这样的嵌套结构。

outerMap.lift("AAA")             // Option[OuterClass]
        .map(_.nestedMap)        // Option[HashMap[String,InnerClass]]
        .flatMap(_.lift("aaa"))  // Option[InnerClass]
        .map(_.name)             // Option[String]
        .getOrElse("no name")    // String

请注意,如果内部或外部映射中的任何一个没有指定的键(分别为 "aaa" 或 "AAA"),那么整个事情将安全地生成默认字符串("no name").

如果找不到 keyHashMap 将 return None,因此无需执行 getOrElse 到 return None 如果找不到密钥。

解决您的问题的一个简单方法是使用 get only,如下所示

将您的第一个 get 更改为

val outerMapTest = outerMap.get("AAA").get

您可以检查输出

println(outerMapTest.name)
println(outerMapTest.nestedMap)

并将第二个 get 更改为

val nestedMap = outerMapTest.nestedMap.get("aaa").get

您可以测试输出

println(nestedMap.name)
println(nestedMap.age)

希望对您有所帮助