'val'或'var',可变或不可变?

Moh*_*deh 13 scala

我可以定义一个var不可变的变量(by ):

var x = scala.collection.immutable.Set("aaaaaa","bbbbbb")
println(x.isInstanceOf[scala.collection.immutable.Set[String]])
x += "cccc"
println(x.isInstanceOf[scala.collection.immutable.Set[String]])
Run Code Online (Sandbox Code Playgroud)

这导致:

true
true
Run Code Online (Sandbox Code Playgroud)

+=方法不是成员scala.collection.immutable.Set,所以发生了什么?

Ken*_*oom 22

编译器会查找x.+= ...,如果找不到它,那么它会尝试将语句转换为x = x + ...(只有在xa时才会成功var,或者x在某些update方法的调用中进行desugars ).由于immutable.Set实现了一个+运算符,并且x是一个var,这就成功了.


Phi*_*l H 6

原始的不可变集仍然没有变化.

继续Ken的回答,+创建了一个新集合,附加了新项目,并返回了新集合,保留了原始集合对象.所以你可以说var y = x; y += "cccc",你会有2套而不是1套:

var x = scala.collection.immutable.Set("aaaaaa","bbbbbb")
println(x.isInstanceOf[scala.collection.immutable.Set[String]])
var y = x
y += "cccc"
println(x)
println(y)
println(x.isInstanceOf[scala.collection.immutable.Set[String]])
println(y.isInstanceOf[scala.collection.immutable.Set[String]])
Run Code Online (Sandbox Code Playgroud)

获得:

> true
> Set(aaaaaa, bbbbbb)
> Set(aaaaaa, bbbbbb, cccc)
> true
> true
Run Code Online (Sandbox Code Playgroud)

您看到数据结构本身仍然是不可变的,但由于您声明了a var,因此赋值是可变的.因此,如果返回它,它可以被重新命名为新对象.如果您更改为声明x为a val,则无法将其重新分配给新地址.

如果你已经使用了可变集,然后xy将指向同一个对象,因为+呼叫会追加现有的一组,而不是返回一个新的(是可变的...):

var x = scala.collection.mutable.Set("aaaaaa","bbbbbb")
println(x.isInstanceOf[scala.collection.immutable.Set[String]])
var y = x
y += "cccc"
println(x)
println(y)
Run Code Online (Sandbox Code Playgroud)

得到:

> Set("aaaaaa","bbbbbb","cccc")
> Set("aaaaaa","bbbbbb","cccc")
Run Code Online (Sandbox Code Playgroud)

瞧.