简体   繁体   English

在Scala中使用从Java导入的不可变的“ val”

[英]Using immutable “val” imported from Java in Scala

I am using following example in Scala to show my confusion: 我在Scala中使用以下示例来显示我的困惑:

import java.util.HashMap
val jhm = new HashMap[String, Int]
jhm.put("myId", 1)
jhm.put("yourId", 2)

And it allows to add into "jhm" 它允许添加到“ jhm”

Now if I do this in Scala: 现在,如果我在Scala中这样做:

val nmap = Map()
nmap += ("myId" -> 1)

It does not allow which is expected. 它不允许哪个是预期的。 My question: why does it allow changing immutable "val" in the first case ? 我的问题:为什么在第一种情况下允许更改不变的“ val”?

val creates an immutable reference, which means that this val will always point to the same object. val创建一个不可变的引用,这意味着此val将始终指向同一对象。 It doesn't guarantee that the object itself will not change its own state. 它不能保证对象本身不会改变其自身的状态。

put() on a HashMap mutates the map and doesn't return a new reference. HashMap上的put()会使地图发生变化,并且不会返回新的引用。 In the second case you are adding a value to an immutable map, so a new map is returned. 在第二种情况下,您将一个值添加到不可变映射中,因此将返回一个新映射。 The Scala equivalent of your Java example would be: Java示例的Scala等效项是:

import collection.mutable.Map

val nmap = Map()[String, Int]
nmap += ("a" -> 1)

you are mixing 2 different 'usages' of immutability. 您正在混合两种不可变的“用法”。

you can have a mutable (var) or immutable (val) reference to something, and that something can be mutable or immutable itself. 您可以对某个对象进行可变的(var)或不可变的(val)引用,并且该对象本身可以是可变的或不可变的。

ex: 例如:

var x = 3
x = 4 // it works, `x` can be reassigned 

val y = 3
y = 4 // it fails, `y` can't be reassigned

the problem is when that 'something', the reference' has an internal state. 问题是当“某物”,“参考”具有内部状态时。 Primitive types like Int or String don't have this problem, but any class can have. IntString这样的原始类型都没有这个问题,但是任何类都可以。 scala collections are a common pain to new scala programmers, because there are mutable collections and immutable collections . 对于新的scala程序员来说,scala集合是一个普遍的痛苦,因为存在可变的集合不可变的集合

The difference is that any operation on an immutable collection returns a new collection, but the original remains the same, while in a mutable collection, the collection itself is modified. 不同之处在于,对不可变集合的任何操作都将返回新集合,但原始集合保持不变,而在可变集合中,集合本身将被修改。

In your case, the scala Map you are using is an immutable Map, and it doesn't contain such method. 在您的情况下,您正在使用的scala Map是不可变的Map,并且不包含此类方法。 You can do myMap ++ (key -> value) and get a new Map. 您可以执行myMap ++ (key -> value)并获取一个新的Map。

A bigger confusion arises when you mix mutability in the references with mutability/state in the objects. 当您将引用中的可变性与对象中的可变性/状态混合在一起时,会产生更大的混乱。 You should play a bit yourself with things like: 您应该自己玩一些类似的事情:

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

if you have any doubts let me/us know so that we can help 如果您有任何疑问,请告诉我/我们,以便我们提供帮助

Management Summary 管理总结

You are not invoking the equivalent methods on equivalent classes. 您没有在等效类上调用等效方法。 Use mutable.Map and replace += with put(...) and both will perform the same. 使用mutable.Map并将+=替换为put(...) ,两者将执行相同的操作。

Detailed Answer 详细答案

There are two distinct operations going on here. 这里有两个不同的操作。 The first one is adding an element to a map. 第一个是向地图添加元素。 The method put(...) on the java Map is equivalent to the put(...) operation in scala, not + , which creates a new Map . java Map上的put(...)方法等效于scala中的put(...)操作, 而不是 + ,它会创建一个新Map The following is totally fine by the compiler: 编译器完全可以满足以下要求:

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)

By putting the the key value pair, map mutates its state. 通过放置键值对, map改变其状态。 This does not cause your error. 这不会导致您的错误。 However you are not invoking the put(...) method, but += . 但是,您不是在调用put(...)方法,而是在调用+= This essentially means two operations: 这实质上意味着两个操作:

  1. call + method 调用+方法
  2. assign the result to the variable 将结果分配给变量

In contrast to put(...) ( ScalaDoc ) + ( ScalaDoc ) does not change the map, but creates a new one similar to immutable.Map . put(...)ScalaDoc+ScalaDoc )相比,它不会更改地图,但会创建类似于immutable.Map的新地图。 After creating the new Map, you try to re-assign it to a val , which raises your compiler error. 创建新Map后,您尝试将其重新分配给val ,这会引起编译器错误。

The same behaviour can be witnessed in java: 在Java中可以看到相同的行为:

final int answer = 42;
answer = 23;

This will result in a compiler error java: cannot assign a value to final variable answer . 这将导致编译器错误java: cannot assign a value to final variable answer

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM