【问题标题】:scala's mutable and immutable set when to use val and varscala 的可变和不可变集何时使用 val 和 var
【发布时间】:2011-06-27 05:42:25
【问题描述】:

我正在阅读 Scala Creator 的 Programming in Scala 一书,我对 Set 的示例有点困惑。

这里是不可变集:

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

这有什么意义?

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

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

【问题讨论】:

    标签: scala


    【解决方案1】:

    不可变数据结构(在本例中为 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) 时间。例如,给定一个大的不可变集合s,应该能够有效地构造s + x,这是一个带有额外元素的新集合。当然,不变性保证s 也被保留。在后台,ss+x 将使用某种具有共享组件的树数据结构进行存储。

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

    【讨论】:

    • 不直接在 API 中,但性能 documented.
    • 如你所料,许多操作都是 O(log n),但应该指出的是,对数的底非常高,以至于它们可以有效地进行 O(1) 操作。实际上,对 Scala 的不可变数据结构的操作与其可变表亲的相应操作在一个常数因子内。
    • 从数学上讲,当然会忽略 big-O 表示法中对数的底,因为它只影响常量前因数。同意 O(log N) 可以非常快地用于实际目的。使不可变数据结构代价高昂的一件事是垃圾收集器的压力。
    【解决方案2】:

    var 允许您重新分配给变量,将其视为 Java 中的普通变量声明。但在上述情况下,即使您重新分配给同一个变量,它也始终是不同的集合,因为您使用的是不可变的集合。

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        我也面临同样的问题。尝试了几个sn-ps,似乎 了解其中的区别。

            // 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
        

        【讨论】:

          猜你喜欢
          • 2012-07-08
          • 2011-07-01
          • 1970-01-01
          • 2011-11-24
          • 2020-10-14
          • 2013-10-05
          • 2016-05-31
          • 2011-05-25
          • 1970-01-01
          相关资源
          最近更新 更多