2

呼叫专家 Scala 开发人员!假设您有一个表示可写数据存储的大对象。您是否对这种常见的类似 Java 的方法感到满意:

val complexModel = new ComplexModel()
complexModel.modify()
complexModel.access(...)

或者您更喜欢:

val newComplexModel = complexModel.withADifference
newComplexModel.access(...)

如果您喜欢这样,并且您有一个客户端访问模型,那么客户端如何知道指向 newComplexModel 而不是 complexModel?从用户的角度来看,您拥有一个可变数据存储。您如何协调这种观点与 Scala 对不变性的强调?

这个怎么样:

var complexModel = new ComplexModel()
complexModel = complexModel.withADifference
complexModel.access(...)

这似乎有点像第一种方法,只是 withADifference 内部的代码似乎比 modify() 内部的代码要做更多的工作,因为它必须创建一个全新的复杂数据对象,而不是修改现有的. (您是否遇到了必须做更多工作来尝试保持不变性的问题?)此外,您现在有一个大范围的 var。

您将如何决定最佳策略?您选择的策略有例外吗?

4

4 回答 4

3

I think the functional way is to actually have Stream containing all your different versions of your datastructure and the consumer just trying to pull the next element from that stream.

But I think in Scala it is an absolutely valid approach to a mutable reference in one central place and change that, while your whole datastructure stays immutable.

When the datastructure becomes more complex you might be interested in this question: Cleaner way to update nested structures which asks (and gets answered) how to actually create new change versions of an immutable data structure that is not trivial.

于 2012-07-08T20:22:15.327 回答
1

您的问题的规范答案是使用Zipper,这是一个关于它的 SO问题

我所知道的 Scala 的唯一实现是在ScalaZ中。

于 2012-07-08T21:41:58.290 回答
1

通过这样的方法名称,modify只有很容易将您识别ComplexModel为 mutator 对象,这意味着它会更改某些状态。这仅意味着这种对象与函数式编程无关,并试图使其不可变只是因为知识有问题的人告诉您 Scala 中的所有内容都应该是不可变的,这只是一个错误。

现在您可以修改您的 api 以便ComplexModel它对不可变数据进行操作,我顺便认为您应该这样做,但您绝对不能尝试将其转换ComplexModel为不可变数据本身。

于 2012-07-08T22:33:49.460 回答
0

不变性只是一个有用的工具,而不是教条。将出现不变性的成本和不便超过其有用性的情况。

a 的大小ComplexModel可能使得创建修改后的副本在内存和/或 CPU 方面足够昂贵,因此可变模型更实用。

于 2012-07-08T20:26:58.173 回答