正如其他人指出的那样,您提出问题的方式使回答有点困难。可能是因为你关注的是Actor,你做的例子有点奇怪。
底线是 Scala 连同它的 Actor 实现,以及 Actor 的 Akka 实现,将很高兴地让你用可变性打自己的脑袋。这似乎是您要问的核心问题,所以如果这就是您想要的,您现在可以停止阅读:)
然而,不变性确实以多种方式提高了并发程序的质量,Scala 的可变性与不变性与 OO 和函数式编程的结合为您提供了很多实现事物的灵活性。
人们似乎没有说的是,一成不变的编程概念需要一种不同于大多数命令式程序员所习惯的编程风格(当我开始学习它时,我当然不习惯它)。许多人似乎认为他们可以像往常一样编写代码,用不可变对象替换可变对象,然后从中获利。不是这样。
如果我们List
举个例子(实际上是看似无处不在的例子),我们可以看到如何编写一些代码来使用它。
我将使用 Akka 的 Future 实现,并用List
Ints 做一些非常愚蠢的事情。算法并不是那么重要。重要的是要认识到不存在的东西——并发保护。我什至不需要考虑并发访问的问题,因为它是完全不可变的。我在下面添加了类型注释,以便清楚地知道发生了什么——Scala 实际上会推断出这一切。
import akka.dispatch.{ExecutionContext, Future, Await}
import akka.util.duration._
import java.util.concurrent.Executors
object Main {
val execService = Executors.newCachedThreadPool()
implicit val execContext = ExecutionContext.fromExecutorService(execService)
def main(args: Array[String]) {
// A Future list of 1's
val flist: Future[List[Int]] = Future { (1 to 5) map { _: Int => 1 } toList }
// The goal is to create a new list of Ints in 25 "iterations" across
// multiple threads
val result: Future[List[Int]] = (1 to 5).foldLeft(flist) { (acc, _) =>
// "Loop" 5 times, creating 5 new lists of Ints, but these 'new' lists
// share most of their content with the previous list
val fs: IndexedSeq[Future[List[Int]]] = (1 to 5) map { i =>
acc map { numlist =>
(i * numlist.sum) :: numlist
}
}
// Reduce the 5 lists we just created back down to one list again, by
// performing a pairwise sum across them all... in the Future
Future.reduce(fs) { (a, l) =>
(a zip l) map { case (i, j) => i + j }
}
}
// Wait for the concurrency to complete and print out the final list
println(Await.result(result, 1 second))
// Shut down the execution system that was running our stuff concurrently
execContext.shutdown()
}
}
// Prints: List(12000000, 3000000, 750000, 187500, 46875, 3125, 3125, 3125, 3125, 3125)
(i * numlist.sum) :: numlist
使用来自 的所有使用位创建的中间列表numlist
。从该循环中出来的 5 个新列表实际上是作为 5 个新值创建的,它们具有指向 的指针numlist
,而不是 5 个全新的列表。即list1 = "newvalue" + oldlist
和list2 = "another new value" + oldlist
等...
编程一成不变地意味着转换模型。获取一个数据结构,将其提供给某物,然后对其进行转换并将其传递给其他人,依此类推。可变编程可以更快、更可靠,也可以更慢,这取决于你在做什么,但最重要的是,正如@mhs 所说,在安全性方面更容易推理。
这如何映射到您通常的命令式编程模式并不明显,因为通常情况下它不会。这也是为什么它对您没有直接意义的原因。就像编码中的其他任何事情一样 - 需要时间才能真正理解新范式。