我在 Scala 中使用以下示例来显示我的困惑:
import java.util.HashMap
val jhm = new HashMap[String, Int]
jhm.put("myId", 1)
jhm.put("yourId", 2)
它允许添加到"jhm"中
现在,如果我在 Scala 中这样做:
val nmap = Map()
nmap += ("myId" -> 1)
它不允许这是预期的。我的问题:为什么它允许在第一种情况下更改不可变的"val"?
val创建了一个不可变的引用,这意味着这个 val 将始终指向同一个对象。它不保证对象本身不会更改其自身的状态。
HashMap 上的 put() 会改变映射并且不会返回新的引用。在第二种情况下,您将向不可变映射添加值,因此返回新映射。Java 示例的 Scala 等效项是:
import collection.mutable.Map
val nmap = Map()[String, Int]
nmap += ("a" -> 1)
您混合了 2 种不同的不可变性"用法"。
你可以有一个可变的(VAR)或不可变的(val)引用,并且某些东西本身可以是可变的或不可变的。
前任:
var x = 3
x = 4 // it works, `x` can be reassigned
val y = 3
y = 4 // it fails, `y` can't be reassigned
问题是当"某物",引用"具有内部状态时。像Int
或String
这样的基元类型没有这个问题,但任何类都可以有这个问题。Scala 集合是新 Scala 程序员常见的痛苦,因为有可变集合和不可变集合。
不同之处在于,对不可变集合的任何操作都会返回一个新集合,但原始集合保持不变,而在可变集合中,集合本身会被修改。
在您的情况下,您使用的 scalaMap
是一个不可变的 Map,它不包含这样的方法。您可以执行myMap ++ (key -> value)
并获取新地图。
当您将引用中的可变性与对象中的可变性/状态混合在一起时,会出现更大的混淆。你应该自己玩一些东西,比如:
val x1 = scala.collection.mutable.ListBuffer(1,2,3) // immutable reference to mutable object
// please, never use this in real code
var x2 = scala.collection.mutable.ListBuffer(1,2,3) // mutable reference to mutable object
// please, try to use this as much as possible
val x3 = scala.collection.immutable.List(1,2,3) // immutable reference to immutable object
var x4 = scala.collection.immutable.List(1,2,3) // mutable reference to immutable object
如果您有任何疑问,请告诉我/我们,以便我们提供帮助
管理摘要
您不会在等效类上调用等效方法。使用mutable.Map
并将+=
替换为put(...)
,两者将执行相同的操作。
详细答案
这里正在进行两种不同的操作。第一个是向地图添加元素。Java Map 上put(...)
的方法等效于 scala 中的put(...)
操作,而不是+
,这会创建一个新的Map
。编译器完全可以满足以下要求:
val map = Map[Int, Int]()
map: scala.collection.mutable.Map[Int,Int] = Map()
map.put(1, 2)
res0: Option[Int] = None
map
res1: scala.collection.mutable.Map[Int,Int] = Map(1 -> 2)
通过放置键值对,map
改变其状态。这不会导致您的错误。但是,您不是在调用put(...)
方法,而是+=
.这实质上意味着两个操作:
- 调用
+
方法 - 将结果分配给变量
put(...)
(ScalaDoc)相反,+
(ScalaDoc)不会更改地图,而是创建一个类似于immutable.Map
的新地图。 创建新 Map 后,您尝试将其重新分配给val
,这将引发编译器错误。
在java中可以看到相同的行为:
final int answer = 42;
answer = 23;
这将导致编译器错误java: cannot assign a value to final variable answer
.