nom*_*mad 11 default scala map
我正在尝试在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()
Run Code Online (Sandbox Code Playgroud)
因此,当用适当的键解决时,地图会让我回到原来的位置.然而,地图本身看起来是空的!在这个例子中,甚至m.size返回0.谁能解释一下这里发生了什么?
dhg*_*dhg 16
这绝对不是一个bug.
行为withDefaultValue是在Map中存储默认值(在您的情况下,是一个可变映射),以便在它们不存在键时返回.这与在找不到键时插入到Map中的值不同.
让我们仔细看看发生了什么.如果我们将默认地图作为单独的变量拉出来以便我们可以随意检查,这将更容易理解; 我们称之为default
import collection.mutable.HashMap
val default = HashMap.empty[Int,Int].withDefaultValue(3)
Run Code Online (Sandbox Code Playgroud)
因此default是一个可变映射(它有自己的默认值).现在我们可以创建m并提供default默认值.
import collection.mutable.{Map => MMap}
val m = HashMap.empty[Int, MMap[Int,Int]].withDefaultValue(default)
Run Code Online (Sandbox Code Playgroud)
现在无论何时m使用缺少的键访问它,它都将返回default.请注意,这与您的行为完全相同,因为它withDefaultValue被定义为:
def withDefaultValue (d: B): Map[A, B]
Run Code Online (Sandbox Code Playgroud)
请注意它是否d: B存在d: => B,因此每次访问默认值时都不会创建新映射; 它会返回相同的对象,我们称之为default.
那么让我们看看会发生什么:
m(1) // Map()
Run Code Online (Sandbox Code Playgroud)
由于密钥1不在m,default因此返回默认值. default这时候是一张空地图.
m(1)(2) = 5
Run Code Online (Sandbox Code Playgroud)
由于m(1)返回default,该操作5存储作为用于在键2的值default.没有任何内容写入地图,m因为完全m(1)解析为default单独的地图.我们可以查看default:
default // Map(2 -> 5)
Run Code Online (Sandbox Code Playgroud)
但正如我们所说,m保持不变
m // Map()
Run Code Online (Sandbox Code Playgroud)
现在,如何实现你真正想要的?而不是使用withDefaultValue,你想要使用getOrElseUpdate:
def getOrElseUpdate (key: A, op: ? B): B
Run Code Online (Sandbox Code Playgroud)
请注意我们如何看待op: => B?这意味着op每次需要时都会重新评估参数.这允许我们在那里放置一个新的Map,并让它成为每个无效键的单独的新Map.让我们来看看:
val m2 = HashMap.empty[Int, MMap[Int,Int]]
Run Code Online (Sandbox Code Playgroud)
此处不需要默认值.
m2.getOrElseUpdate(1, HashMap.empty[Int,Int].withDefaultValue(3)) // Map()
Run Code Online (Sandbox Code Playgroud)
键1不存在,因此我们插入一个新的HashMap,并返回该新值.我们可以检查它是否按预期插入.请注意,1映射到新添加的空映射,并且由于上面解释的行为,它们3未添加到任何地方.
m2 // Map(1 -> Map())
Run Code Online (Sandbox Code Playgroud)
同样,我们可以按预期更新Map:
m2.getOrElseUpdate(1, HashMap.empty[Int,Int].withDefaultValue(1))(2) = 6
Run Code Online (Sandbox Code Playgroud)
并检查它是否已添加:
m2 // Map(1 -> Map(2 -> 6))
Run Code Online (Sandbox Code Playgroud)