1

考虑以下:

scala> val myset = Set(1,2)
myset: scala.collection.immutable.Set[Int] = Set(1, 2)

scala> myset += 3
<console>:9: error: reassignment to val
              myset += 3
                    ^

scala> var myset = Set(1,2)
myset: scala.collection.immutable.Set[Int] = Set(1, 2)

scala> myset += 3

scala> myset
res47: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

在一种情况下,我可以添加“alex”,而在另一种情况下,我不能。我知道 val 和 var 之间的区别。然而,在这两种情况下让我感到困惑的是,Scala 告诉我 Set 是不可变的,但它允许不同的行为。

我不想那样做,因为在情况下 myset 是一个 val,而在一个情况下它是一个 var。我想要一个比这更深入的答案来解释为什么在这两种情况下 Scala 都说 myset 是一个不可变的集合,但是却以不同的方式对待两者。因为它是反直觉的。

例如,使用可变集和将不可变集声明为 var 有什么区别吗?为什么 scala 会让你改变规则?如果当它说不可变时它意味着它不是更好吗?

谢谢。

4

3 回答 3

3

首先让我们翻译+=通话

val myset = Set(1,2)
myset = myset + 3 //this is what the compiler does for myset += 3

这意味着我们实际上是在调用+方法 on Set,其scaladoc

使用附加元素创建一个新集合,除非该元素已经存在。

因此,代码试图做的是使用添加的元素创建一个 Set元素并将其重新分配给不可变引用 myset

现在,如果我们将引用更改为可变引用(使用var),那么您可以使用新创建的和不可变的重新分配它 Set(1,2,3)

原来的 Set(1, 2) 仍然是不可变的,没有规则被破坏。让我们用一个案例来解释一下

var myset = Set(1,2)
val holdIt = Some(myset)
myset += 3
println(myset) // will print Set(1, 2, 3)
println(holdIt)// will print Some(Set(1, 2))

如您所见,由Set捕获的原始Option从未更改,我们只是将其变量引用重新分配给新创建的Set

于 2013-02-09T11:57:21.683 回答
2

当您使用不可变 Set 时,将创建一个新 Set 并重新分配给var,这在使用 时是不可能的val。但是一个可变的 Set 可以被改变。虽然以下不是一个完美的保存演示,但它仍然表明使用不可变 Set 创建了一个新对象,并且可变 Set 实例保持不变:

scala> var set1 = Set(1, 2)
set1: scala.collection.immutable.Set[Int] = Set(1, 2)

scala> System.identityHashCode(set1)
res0: Int = 2119337193

scala> set1 += 3

scala> System.identityHashCode(set1)
res2: Int = 1866831260

scala> var set2 = collection.mutable.Set(1, 2)
set2: scala.collection.mutable.Set[Int] = Set(2, 1)

scala> System.identityHashCode(set2)
res3: Int = 594308521

scala> set2 += 3
res4: scala.collection.mutable.Set[Int] = Set(2, 1, 3)

scala> System.identityHashCode(set2)
res5: Int = 594308521
于 2013-02-09T12:00:26.710 回答
2

考虑myset作为指针和 Set(1,2)对象

如果val myset指针只分配一次并且不能指向不同的对象(即指针是不可变的),而在这种情况下var myset可以分配任意时间并且可以指向不同的对象(即指针是可变的

在这两种情况下,对象Set(1,2)都是不可变的。

当你这样做

scala> val myset = Set(1,2)
myset: scala.collection.immutable.Set[Int] = Set(1, 2)

scala> myset += 3
<console>:9: error: reassignment to val
              myset += 3
                    ^

myset += 3 actually gives you a new Set with 3 appended to it..

Since the myset pointer is immutable you cannot reassign to the new object returned by the + method.

where as in case of

scala> var myset = Set(1,2)
myset: scala.collection.immutable.Set[Int] = Set(1, 2)

scala> myset += 3

Since myset pointer is mutable you can reassign to the new object returned by the + method.

于 2013-02-09T12:07:55.593 回答