如何在保留不变性的同时访问Scala中的复杂数据结构?

时间:2012-07-08 19:24:23

标签: scala data-structures functional-programming immutability

致电专家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 个答案:

答案 0 :(得分:3)

我认为实用的方法是让Stream包含所有不同版本的数据结构,而消费者只是试图从该流中提取下一个元素。

但我认为在Scala中,它是一个绝对有效的方法,可以在一个中心位置进行可变引用,并改变它,同时整个数据结构保持不变。

当数据结构变得更加复杂时,您可能会对这个问题感兴趣:Cleaner way to update nested structures询问(并得到答案)如何实际创建不可变数据结构的新变更版本。这不是一件容易的事。

答案 1 :(得分:1)

您问题的规范回答是使用Zipper,一个是SO question about it

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

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

不变性只是一种有用的工具,而不是教条。如果不可变性的成本和不便超过其有用性,就会出现这种情况。

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