致电专家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。
您如何决定最佳策略?您选择的策略有例外吗?
答案 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方面足够昂贵,以致可变模型更实用。