为什么scala.collection.mutable.Map的withDefaultValue无法正确保留默认值?
Scala可变Map使用withDefaultValue后的行为解析
先看你给出的代码复现:
Welcome to Scala 2.13.5 (OpenJDK 64-Bit Server VM, Java 1.8.0_312). ... import scala.collection.mutable.{Map => MMap, ListBuffer => MList} import scala.collection.mutable.{Map=>MMap, ListBuffer=>MList} val m = MMap[String, MList[String]]().withDefaultValue(MList[String]()) val m: scala.collection.mutable.Map[String,scala.collection.mutable.ListBuffer[String]] = Map() m("a") val res0: scala.collection.mutable.ListBuffer[String] = ListBuffer() m("a").addOne("b") val res1: scala.collection.mutable.ListBuffer[String] = ListBuffer(b) m val res2: scala.collection.mutable.Map[String,scala.collection.mutable.ListBuffer[String]] = Map() m.keys val res3: Iterable[String] = Set() m("a") val res4: scala.collection.mutable.ListBuffer[String] = ListBuffer(b)
核心原因拆解
- withDefaultValue的作用逻辑:这个方法并没有改变Map的存储行为,它只是给Map绑定了一个固定的默认实例。当你访问不存在的键时,Map会直接返回这个预先创建好的实例,并不会将该键和默认实例添加到Map的内部存储中。而且所有不存在的键,返回的都是同一个实例。
- Map为空的原因:调用
m("a")时,仅仅是触发了默认值的返回,没有执行任何向Map中添加键值对的操作,所以Map的内部存储始终是空的,打印m或者m.keys自然看不到键"a"。 - 再次访问能看到修改的原因:因为每次访问不存在的键,返回的都是同一个ListBuffer实例。第一次访问时拿到这个空实例,调用
addOne("b")修改了它的内容;第二次访问时返回的还是这个已经被修改的实例,所以能看到ListBuffer(b)。
如果你想实现“访问不存在的键时自动添加到Map”
如果你的需求是访问不存在的键时,自动创建新的ListBuffer并添加到Map中,可以用withDefault(注意不是withDefaultValue)来实现:
val m = MMap[String, MList[String]]().withDefault { key => val newList = MList[String]() m(key) = newList // 将新创建的ListBuffer添加到Map中 newList }
这样调用m("a")时,会自动创建新的ListBuffer并绑定到键"a",后续修改这个ListBuffer时,Map中也会保留对应的键值对。
内容的提问来源于stack exchange,提问作者Scoobie
相关产品推荐
相关产品推荐

