scala的可变和不可变集何时使用val和var

时间:2011-06-27 05:42:25

标签: scala

我正在阅读Scala Creator编写的Scala编程书,我对Set的例子有点混淆。

这里是Immutable Set:

var jetSet = Set("Boeing", "Airbus")
jetSet += "Lear"
println(jetSet.contains("Cessna"))

这有什么意义?

该集合是不可变的,但变量jetSet是可变的。 1)所以每次我用+ =添加到集合中它会创建一个新集合?那么变量指向内存中的新集合?

2)不应该是: val jetSet = set("cow","sheep","duck")?为什么它必须是var?是否有理由将var用于不可变集?

4 个答案:

答案 0 :(得分:16)

不可变数据结构(在本例中为Set)的优点是它们是持久的。例如:

var jetSet1 = Set("Boeing", "Airbus")
val jetSet2 = jetSet1 // ... imagine jetSet2 is somewhere else in the program
jetSet1 += "Lear"
assert(!jetSet2.contains("Lear"))

这些Set对象的不变性使得更容易推理该程序,因为jetSet1变量的更新在代码的其他部分没有副作用(在这种情况下,jetSet2的任何地方都是用过的)。虽然从这个例子中不清楚,但有时候将不可变值存储在可变var引用中是很方便的。大多数情况下,var的范围有限(例如,函数的本地范围)。

不可变数据结构通常具有非常高效的巧妙实现。不幸的是,Scala集合API没有关于性能的详细记录,但我预计大多数操作大致为O(log N)时间。例如,给定一个大的不可变Set s,应该能够有效地构造s + x,一个带有额外元素的新Set。当然,不变性保证了s也得以保留。在幕后,ss+x将使用某种具有共享组件的树数据结构进行存储。

您的问题标题表明您也在寻找有关使用valvar的建议。经验法则是,只要您方便,就可以使用val。如果需要var,则尝试尽可能地限制变量的范围。

答案 1 :(得分:6)

var允许您重新分配给变量,将其视为Java中的正常变量声明。但是在上面的例子中,即使你重新分配给同一个变量,它也总是一个不同的集合,因为你使用的是不可变的变量。

示例的要点是表明即使您尝试“修改”不可变集合,修改也会创建一个新集合,而不是触及原始集合。如果作者使用val(在Java中的final行),他将不得不在范围中引入一个变量来保存新的不可变集。我认为var可能用于保持示例简单。

答案 2 :(得分:0)

如果您使用+=,则无法valval/var/def适用于符号,而不适用于其值/实现 试试val ...你会得到一个编译error

答案 3 :(得分:0)

我也面临着同样的问题。尝试了一些片段,似乎 已经了解了区别。

    // immutable reference to an immutable object
    val seta = Set("A", "B")
    seta += "C" //throws an error as the object is immutable
    seta = Set("C") //throws error as the reference is immutable

    // mutable reference to an immutable object
    var seta = Set("A", "B")
    val setab = seta //backup the reference
    set += "C" //creates and new object
    println(setab == seta) //false as seta is a dfferent object now

    //immutable reference to mutable object
    val seta = mutable.Set("A", "B")
    val setab = seta //backup the reference
    set += "C" //modifies the existing object
    println(setab == seta) //true as seta is the same object and same as 
    setab