我正在阅读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用于不可变集?
答案 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
也得以保留。在幕后,s
和s+x
将使用某种具有共享组件的树数据结构进行存储。
您的问题标题表明您也在寻找有关使用val
或var
的建议。经验法则是,只要您方便,就可以使用val
。如果需要var
,则尝试尽可能地限制变量的范围。
答案 1 :(得分:6)
var
允许您重新分配给变量,将其视为Java中的正常变量声明。但是在上面的例子中,即使你重新分配给同一个变量,它也总是一个不同的集合,因为你使用的是不可变的变量。
示例的要点是表明即使您尝试“修改”不可变集合,修改也会创建一个新集合,而不是触及原始集合。如果作者使用val
(在Java中的final
行),他将不得不在范围中引入一个变量来保存新的不可变集。我认为var
可能用于保持示例简单。
答案 2 :(得分:0)
如果您使用+=
,则无法val
。 val/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