具有可变默认值的 Scala Map 始终指向同一个对象
Scala Map with mutable default value always point to the same object
Scala version:3.1
我想创建一个 String -> Int 映射,每个键可以指向多个 Int。
因此我选择默认可变的地图Buffer[Int]
。
但是似乎所有的键总是指向同一个Buffer[Int]
请注意,第一个 m("a") += 1
也很奇怪,在此 +=
之后它什么也不打印,但默认值已更改,因此它打印 two 1 在下 println
.
此外,如何解决 mutable.Map
的 +=
被 Buffer
的 +=
覆盖的问题。如果密钥不存在,我希望地图插入一个新的 Buffer
,然后调用 buffer
.
的 +=
import scala.collection.mutable
val m: mutable.Map[String, mutable.Buffer[Int]] =
mutable.HashMap.empty.withDefaultValue(mutable.Buffer.empty)
m("a") += 1
println(m) // Map()
m("a") = m("a") += 1
println(m) // Map(a -> ArrayBuffer(1, 1))
m("b") = m("b") += 2 // Map(a -> ArrayBuffer(1, 1, 2), b -> ArrayBuffer(1, 1, 2)) , not expecting this, key is correct but
println(m) // Map(a -> ArrayBuffer(1, 1, 2), b -> ArrayBuffer(1, 1, 2))
m("a") = m("a") += 2
println(m) // Map(a -> ArrayBuffer(1, 1, 2, 2), b -> ArrayBuffer(1, 1, 2, 2)) ,
// this is not as I expected. The keys are correct, however their values are all the same ArrayBuffer
TL;DR: withDefaultValue
在这里没用。
注意 signature of withDefaultValue
是:
def withDefaultValue(d: V): Map[K, V]
参数d
取值,而不是by name(=> V
),因此只计算一次。因此,原始映射中不存在的任何键都将 return 与您创建一次的空缓冲区相同。
您得到的 withDefaultValue
(和 withDefault
)是一个新的 map-like 对象,而不是原始地图。只有分配结果 (m("a") = ...
) 才会改变它。
Note: The default is only used for apply. Other methods like get, contains, iterator, keys, etc. are not affected by withDefaultValue.
考虑这个例子:
val m = new HashMap[Integer, Buffer[String]]()
val mm = m.withDefault(_ => Buffer.empty)
mm(1).append("4")
mm(1) // ArrayBuffer()
你可能想要的是getOrElseUpdate
(如果你愿意,你可以定义一个辅助函数)带有签名
getOrElseUpdate(key: K, defaultValue: => V): V
注意这次如何按名称调用 defaultValue
,每次调用都会创建一个新缓冲区:
val m: mutable.Map[String, mutable.Buffer[Int]] =
mutable.HashMap.empty
def mm(key: String): mutable.Buffer[Int] = m.getOrElseUpdate(key, mutable.Buffer.empty)
mm("a") += 1
mm("b") += 2
// now buffers at `a` and `b` are distinct
Scala version:3.1
我想创建一个 String -> Int 映射,每个键可以指向多个 Int。
因此我选择默认可变的地图Buffer[Int]
。
但是似乎所有的键总是指向同一个Buffer[Int]
请注意,第一个 m("a") += 1
也很奇怪,在此 +=
之后它什么也不打印,但默认值已更改,因此它打印 two 1 在下 println
.
此外,如何解决 mutable.Map
的 +=
被 Buffer
的 +=
覆盖的问题。如果密钥不存在,我希望地图插入一个新的 Buffer
,然后调用 buffer
.
+=
import scala.collection.mutable
val m: mutable.Map[String, mutable.Buffer[Int]] =
mutable.HashMap.empty.withDefaultValue(mutable.Buffer.empty)
m("a") += 1
println(m) // Map()
m("a") = m("a") += 1
println(m) // Map(a -> ArrayBuffer(1, 1))
m("b") = m("b") += 2 // Map(a -> ArrayBuffer(1, 1, 2), b -> ArrayBuffer(1, 1, 2)) , not expecting this, key is correct but
println(m) // Map(a -> ArrayBuffer(1, 1, 2), b -> ArrayBuffer(1, 1, 2))
m("a") = m("a") += 2
println(m) // Map(a -> ArrayBuffer(1, 1, 2, 2), b -> ArrayBuffer(1, 1, 2, 2)) ,
// this is not as I expected. The keys are correct, however their values are all the same ArrayBuffer
TL;DR: withDefaultValue
在这里没用。
注意 signature of withDefaultValue
是:
def withDefaultValue(d: V): Map[K, V]
参数d
取值,而不是by name(=> V
),因此只计算一次。因此,原始映射中不存在的任何键都将 return 与您创建一次的空缓冲区相同。
您得到的 withDefaultValue
(和 withDefault
)是一个新的 map-like 对象,而不是原始地图。只有分配结果 (m("a") = ...
) 才会改变它。
Note: The default is only used for apply. Other methods like get, contains, iterator, keys, etc. are not affected by withDefaultValue.
考虑这个例子:
val m = new HashMap[Integer, Buffer[String]]()
val mm = m.withDefault(_ => Buffer.empty)
mm(1).append("4")
mm(1) // ArrayBuffer()
你可能想要的是getOrElseUpdate
(如果你愿意,你可以定义一个辅助函数)带有签名
getOrElseUpdate(key: K, defaultValue: => V): V
注意这次如何按名称调用 defaultValue
,每次调用都会创建一个新缓冲区:
val m: mutable.Map[String, mutable.Buffer[Int]] =
mutable.HashMap.empty
def mm(key: String): mutable.Buffer[Int] = m.getOrElseUpdate(key, mutable.Buffer.empty)
mm("a") += 1
mm("b") += 2
// now buffers at `a` and `b` are distinct