带有 var 的不可变映射或带有 val 的可变映射?

Immutable Map with var or Mutable map with val?

以下两个代码段中哪个更有效且行为正确?

// snippet 1
var map = Map[String, Int]()   // immutable map with var
map.synchronized(map += "hello" -> 1)
map.synchronized(map -= "hello")

// snippet 2
val mmap = scala.collection.mutable.Map[String, Int]()
mmap.synchronized(mmap += "hello" -> 1)
mmap.synchronized(mmap -= "hello")

编辑:我正在查看并发访问地图的情况,其中多个不同的参与者共享同一张地图并想要修改它。此外,链接的问题涉及 varval 的一般情况,而我需要对 Map 集合类型有一些了解。

这取决于可变对象和不可变对象各有利弊。

不可变对象使并发编程更容易、更安全,并且您可以轻松地对它们进行推理。围绕 JVM 并发发生的大多数运行时错误都是因为共享可变状态。

如果您的对象变大,仅仅为了保持不可变状态而复制对象是没有意义的。当你设计你的算法时,你必须明智地思考。

soote: Is there a reason you cannot place this map inside an actor, and have other actors use messages to modify/read it?

Jus12: @soote On second thought, you are right! I will implement it using proper actor model.

soote 确实是正确的:因为您显然使用的是 actor 系统,所以地图应该驻留在 actor 中。通常,当表示 actor 内部的可变状态时,应该使用具有 var 的不可变数据结构,而不是具有 val 的可变数据结构。这样做的原因是为了防止该状态泄漏到 actor 的边界之外。这是一个使用 Akka 的具体示例:

case object GetState
case class Add(key: String, value: Int)
case class Remove(key: String)

class MyActor extends Actor {
  val state = mutable.Map[String, Int]()

  def receive = {
    case GetState =>
      sender ! state
    case Add(k, v) =>
      state += (k -> v)
    case Remove(k) =>
      state -= k
  }
}

当上述 actor 收到 GetState 消息时,它会将其内部映射发送给发送者。由于映射是可变的,发送者现在可以从 actor 外部修改该映射 ,从而允许破坏 actor 状态的可能性。为防止这种泄漏,限制 actor 本身的可变性:

class MyActor extends Actor {
  var state = Map[String, Int]() // immutable map

  def receive = {
    case GetState =>
      sender ! state
    case Add(k, v) =>
      state = state + (k -> v)
    case Remove(k) =>
      state = state - k
  }
}

现在 MyActor 可以安全地将其状态发送给其他参与者,因为它的状态是一个不可变的映射。