2013-02-09 56 views
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) 

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

我不想只是因为在oncase myset是一个val,在一个它是一个变种。我想得到更深入的回答,而不是解释为什么在这两种情况下Scala都说myset是一个不可变的集合,但两者的处理方式不同。因为这是违反直觉的。

例如,使用可变集合并将不可变集合声明为var有任何区别吗? 为什么斯卡拉让你弯曲规则?如果说它是不可变的,它会不会更好呢?

谢谢。

回答

3

首先,让我们来翻译+=呼叫

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

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

创建集与额外的元素,除非元素已经存在。因此

什么代码试图做的是创建一个新的Set与添加的元素,并将其重新分配给一成不变参考myset

现在,如果我们改变引用一个可变的一个(使用var),那么你可以用新做的和不可改变Set(1,2,3)

原设定重新分配它(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

2

当你使用一个不可变的Set,将会创建一个新的Set并将其重新分配到var,这在使用val时是不可能的。但是一个可变的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 
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实际上给你一个新的Set3追加到它..

由于myset指针是不可变的,你不能重新分配给由+方法返回的新object

,其中在

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

scala> myset += 3 

由于myset指针的情况下是可变的,你可以重新分配给由+方法返回的新object