我从available article所有关于此主题的内容是
不可变对象的主要优点是进行并发编程。 因此,如果任何应用程序使用如此多的线程,那么我们可以使用不变性。
这里我的问题是:如果应用程序不需要多个线程,仍然首选不可变编程?因为为每一次更改创建一个新的对象副本可能会非常昂贵。(如果是的话)
答案 0 :(得分:1)
考虑一下:
class Time(t: Double) {
private var time = t // Danger: mutable field
def getTime = time
def setTime(t: Double): Unit = time = t
}
val startAt = new Time(5.0)
val someOtherTime = startAt
someOtherTime.setTime(10.0)
// What does startAt.getTime return?
在这个简单的示例中,您可能(或可能不会)惊讶地发现,在someOtherTime.setTime(10.0)
返回后,startAt.getTime
将具有值10.0
而不是5.0
。你有没有期待,特别是考虑到startAt
是val
?
鉴于您已经看过代码,也许这是预期的。但是,如果您只是使用Time
而没有查看其内部结构,我猜测您会对此行为感到非常惊讶。可变对象的状态可以在您不知道更改的情况下进行更改 - 尤其是在必须同步访问Time.time
的多线程环境中 - 但即使是单线程情况也会引入意外的复杂性。
保持对象不可变使得它们易于推理。当这些对象代表值类型时,不变性实际上是必不可少的。 (在任何不可变的主要编程语言或库中命名单个值类型。)
关于单线程与多线程编码的另一个观点:如果您正在编写单线程应用程序,那么您可能会完全忽略线程安全问题。但是,我认为在一般情况下这有点短视。所有新处理器都有多个内核,并且有迹象表明处理器将在未来几年内获得越来越多的内核。如果您想编写响应迅速的高性能代码,那么您将需要使用线程安全库来编写多线程应用程序。
如果您正在编写非线程安全的代码,并且它包含许多展示共享可变状态的可变对象,那么您将不得不做一个大量的重构使其适用于多线程应用程序。另一方面,如果你的对象是不可变的,并且没有共享的可变状态,那么这项工作将变得更加容易。
顺便提及,完全可以在函数,类等中使用可变状态,条件是不共享可变状态(即,在外部可见)。这样你就可以获得可变状态性能的好处,而没有缺点。
答案 1 :(得分:0)
我完全同意即使在单线程程序中,不可变对象也更容易推理。但是,有时使用可变数据更为实际,例如,如果性能至关重要(我们的计算机针对变异操作进行了优化),或者您正在使用的库本身具有状态。
我还要补充一点,Scala不是编写纯功能程序的最佳语言。 Haskell,PureScript,Idris等语言更适合恕我直言任务。对于某些多线程程序,以纯函数方式编写Scala程序绝对值得花费额外的麻烦。