可变变量与可变集合

MyT*_*tle 9 functional-programming scala

在我的应用程序中,我需要能够交换集合中的元素.所以我有一个选择:

  1. 使用声明为的可变集合 val
  2. 或使用声明为的var永久集合(并始终重新分配新集合var)

但是在Scala中(在函数式编程中),可变性总是避免.那么更糟糕的是:使用声明的可变集合val或声明为不可变的集合var

Rex*_*err 10

这实际上取决于您是否需要广泛分享该集合.可变集合的优点是它通常比不可变集合更快,并且更容易让单个对象传递而不必确保您可以从不同的上下文设置var.但是既然它们可以从你身下改变,你甚至可以在单线程环境中小心:

import collection.mutable.ArrayBuffer
val a = ArrayBuffer(1,2,3,4)
val i = a.iterator
i.hasNext             // True
a.reduceToSize(0)
i.next                // Boom!

java.lang.IndexOutOfBoundsException: 0
at scala.collection.mutable.ResizableArray$class.apply(ResizableArray.scala:43)
    ...
Run Code Online (Sandbox Code Playgroud)

因此,如果它被广泛使用,你应该考虑是否可以适当小心避免这样的问题.使用var不可变集合通常更安全; 然后你可能会过时,但至少你不会因为段错而堕落.

var v = Vector(1,2,3,4)
val i = v.iterator
i.hasNext            // True
v = Vector[Int]()
i.next               // 1
Run Code Online (Sandbox Code Playgroud)

但是,现在,您必须v从任何可能修改它的方法(至少包含它的类之外)作为返回值传递.如果您忘记更新原始值,这也可能会导致问题:

var v = Vector(1,2,3,4)
def timesTwo = v.map(_ * 2)
timesTwo
v       // Wait, it's still 1,2,3,4?!
Run Code Online (Sandbox Code Playgroud)

但是这也没有更新,是吗?:

a.map(_ * 2)    // Map doesn't update, it produces a new copy!
Run Code Online (Sandbox Code Playgroud)

所以,作为一般规则,

  1. 性能要求您使用一个 - 使用它
  2. 方法中的局部范围 - 使用可变集合
  3. 与其他线程/类共享 - 使用不可变集合
  4. 在类中实现,简单的代码 - 使用可变集合
  5. 在类中实现,复杂的代码 - 使用不可变的

但是你应该经常违反这一点,因为你坚持下去.


om-*_*nom 1

可变性是一头野兽,你最好把它关在笼子里。理想情况下,在像 scala 可变集合这样经过充分测试和高度使用的笼子类型中。