'val' или 'var', изменяемый или неизменный?

Я могу определить переменную (по var), которая неизменна:

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]])

Это приводит к:

true
true

+= метод не входит в scala.collection.immutable.Set, так что происходит?

Ответ 1

Компилятор ищет x.+= ..., и если он не может его найти, он пытается преобразовать оператор в x = x + ... (который выполняется только тогда, когда x является var или x desugars в вызов некоторого метода update). Так как immutable.Set реализует оператор +, а x - это var, это удается.

Ответ 2

Исходный неизменяемый набор не изменяется.

Продолжая Кен ответ, + создал новый набор, добавил новый элемент и вернул новый набор, оставив исходный заданный объект без изменений. Таким образом, вы могли бы сказать 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]])

Получение:

> true
> Set(aaaaaa, bbbbbb)
> Set(aaaaaa, bbbbbb, cccc)
> true
> true

Вы видите, что сама структура данных по-прежнему остается неизменной, но поскольку вы объявили var, назначение является изменяемым. Таким образом, он может быть переназначен на новый объект, если он возвращается. Если вы измените на объявление x как val, вы не сможете переназначить его на новый адрес.

Если вы использовали набор mutable, то x и y будут указывать на один и тот же объект, потому что вызов + добавил бы существующий набор, а не возвращал новый (будучи изменчивым...):

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)

Get:

> Set("aaaaaa","bbbbbb","cccc")
> Set("aaaaaa","bbbbbb","cccc")

Voila.