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



我在 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

问题是当"某物",引用"具有内部状态时。像IntString这样的基元类型没有这个问题,但任何类都可以有这个问题。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(...)方法,而是+=.这实质上意味着两个操作:

  1. 调用+方法
  2. 将结果分配给变量
put(...)

(ScalaDoc)相反,+(ScalaDoc)不会更改地图,而是创建一个类似于immutable.Map的新地图。 创建新 Map 后,您尝试将其重新分配给val,这将引发编译器错误。

在java中可以看到相同的行为:

final int answer = 42;
answer = 23;

这将导致编译器错误java: cannot assign a value to final variable answer.

最新更新