我正在尝试在 Scala 中构造嵌套映射,其中外部映射和内部映射都使用“withDefaultValue”方法。例如,以下内容:
val m = HashMap.empty[Int, collection.mutable.Map[Int,Int]].withDefaultValue( HashMap.empty[Int,Int].withDefaultValue(3))
m(1)(2)
res: Int = 3
m(1)(2) = 5
m(1)(2)
res: Int = 5
m(2)(3) = 6
m
res : scala.collection.mutable.Map[Int,scala.collection.mutable.Map[Int,Int]] = Map()
因此,当使用适当的键寻址时, map 会返回我输入的内容。但是, map 本身显示为空!在此示例中,甚至 m.size 也返回 0。谁能解释一下这是怎么回事?
最佳答案
简短回答
这绝对不是一个错误。
长答案
withDefaultValue
的行为是在 Map 中存储默认值(在您的情况下是可变映射),以便在键不存在时返回。这与未找到键时插入到 Map 中的值不同。
让我们仔细看看发生了什么。如果我们将默认映射作为单独的变量取出,以便我们可以随意检查,会更容易理解;我们称之为默认
import collection.mutable.HashMap
val default = HashMap.empty[Int,Int].withDefaultValue(3)
所以 default
是一个可变映射(有自己的默认值)。现在我们可以创建 m
并指定 default
作为默认值。
import collection.mutable.{Map => MMap}
val m = HashMap.empty[Int, MMap[Int,Int]].withDefaultValue(default)
现在,每当使用丢失的 key 访问 m
时,它将返回 default
。请注意,这与您的行为完全相同,因为 withDefaultValue
定义为:
def withDefaultValue (d: B): Map[A, B]
请注意,它是 d: B
而不是 d: => B
,因此每次访问默认值时不会创建新 map ;它将返回完全相同的对象,我们称之为default
。
让我们看看会发生什么:
m(1) // Map()
由于键 1 不在 m
中,因此返回默认值 default
。此时的default
是一个空Map。
m(1)(2) = 5
由于 m(1)
返回 default
,因此此操作将 5 作为键 2 的值存储在 default
中。没有向 Map m
写入任何内容,因为 m(1)
解析为 default
,它完全是一个单独的 Map。我们可以通过查看default
来检查这一点:
default // Map(2 -> 5)
但正如我们所说,m
保持不变
m // Map()
<小时/>
现在,如何实现您真正想要的?您希望使用 getOrElseUpdate
,而不是使用 withDefaultValue
:
def getOrElseUpdate (key: A, op: ⇒ B): B
注意我们如何看到op: => B
吗?这意味着每次需要时都会重新评估参数op
。这允许我们在其中放置一个新的 Map,并使其成为每个无效键的单独的新 Map。我们来看看:
val m2 = HashMap.empty[Int, MMap[Int,Int]]
此处不需要默认值。
m2.getOrElseUpdate(1, HashMap.empty[Int,Int].withDefaultValue(3)) // Map()
键 1 不存在,因此我们插入一个新的 HashMap,并返回该新值。我们可以检查它是否按照我们的预期插入。请注意,1 映射到新添加的空映射,并且由于上面解释的行为,它们 3 没有添加到任何地方。
m2 // Map(1 -> Map())
同样,我们可以按预期更新 map :
m2.getOrElseUpdate(1, HashMap.empty[Int,Int].withDefaultValue(1))(2) = 6
并检查它是否已添加:
m2 // Map(1 -> Map(2 -> 6))
关于scala - Scala 中的嵌套默认映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8904823/