使用“不可变”;val";在Scala中从Java导入
我在Scala中使用以下示例来说明我的困惑:使用“不可变”;val";在Scala中从Java导入,java,scala,Java,Scala,我在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创建一个不
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)
您正在混合两种不同的不变性“用法” 您可以对某个对象进行可变(var)或不可变(val)引用,并且该对象本身可以是可变的或不可变的 例: 问题是当“某物”时,引用“具有内部状态”。像
Int
或String
这样的基本类型没有这个问题,但任何类都可能有这个问题。scala集合对于新的scala程序员来说是一个常见的难题,因为存在和
不同之处在于,对不可变集合的任何操作都会返回一个新集合,但原始集合保持不变,而在可变集合中,集合本身会被修改
在您的例子中,您使用的scalaMap
是一个不可变的映射,它不包含这样的方法。您可以执行myMap++(键->值)
并获得一个新地图
当您将引用中的可变性与对象中的可变性/状态混合在一起时,会出现更大的混乱。你应该自己玩一些东西,比如:
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映射上的方法put(…)
相当于scala中的put(…)
操作,not+
,它创建了一个新的映射。编译器完全可以执行以下操作:
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(…)
()+
()不会更改映射,而是创建一个类似于immutable.map
的新映射。
创建新映射后,尝试将其重新分配给val
,这会引发编译器错误
在java中也可以看到同样的行为:
final int answer = 42;
answer = 23;
这将导致编译器错误java:cannot assign value to final variable answer
put只是在添加值,而不是在第二个实例中创建不可变映射时更改jhm的引用,然后说put并更改nmap的实例。但是,当它是Java类的对象,而当它是纯Scala类型时,则不允许更改。@NKM val并不意味着对象本身不能更改。它只是意味着引用不能更改。使用Java HashMap,您可以改变一个可变对象,但是对它的引用仍然指向同一个对象。对于Scala不可变映射,添加键值对将返回一个新映射,因此引用将更改。@NKM:valval
不会更改。被val
引用的对象确实存在。我知道了。谢谢你的详细解释。
final int answer = 42;
answer = 23;