简体   繁体   English

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

[英]how to access complex data structures in Scala while preserving immutability?

Calling expert Scala developers! 致电Scala专业开发人员! Let's say you have a large object representing a writable data store. 假设您有一个代表可写数据存储的大对象。 Are you comfortable with this common Java-like approach: 您是否喜欢这种常见的类似Java的方法:

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

Or do you prefer: 还是您更喜欢:

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

If you prefer that, and you have a client accessing the model, how is the client going to know to point to newComplexModel rather than complexModel? 如果您愿意这样做,并且有一个客户端访问模型,那么客户端将如何知道指向newComplexModel而不是complexModel? From the user's perspective you have a mutable data store. 从用户的角度来看,您具有可变的数据存储。 How do you reconcile that perspective with Scala's emphasis on immutability? 您如何将这种观点与Scala对不变性的强调相协调?

How about this: 这个怎么样:

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

This seems a bit like the first approach, except that it seems the code inside withADifference is going to have to do more work than the code inside modify(), because it has to create a whole new complex data object rather than modifying the existing one. 这似乎有点类似于第一种方法,除了withADifference内部的代码似乎比Modify()内部的代码需要做更多的工作外,因为它必须创建一个全新的复杂数据对象而不是修改现有的对象。 (Do you run into this problem of having to do more work in trying to preserve immutability?) Also, you now have a var with a large scope. 您是否遇到了在保持不变性方面不得不做更多工作的问题?)而且,您现在拥有一个具有较大范围的var。

How would you decide on the best strategy? 您将如何决定最佳策略? Are there exceptions to the strategy you would choose? 您选择的策略是否有例外?

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. 我认为功能性的方法是实际上使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. 但是我认为在Scala中,这是绝对有效的方法,可在一个中心位置进行可变引用,并在您整个数据结构保持不变的情况下进行更改。

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. 当数据结构变得更加复杂时,您可能会对以下问题感兴趣: 一种更清晰的方法来更新嵌套结构 ,该结构询问(并得到回答)如何实际创建不平凡的不可变数据结构的新更改版本。

The canonical answer to your question is using Zipper , one SO question about it . 对您问题的规范答案是使用Zipper ,这是一个有关SO的问题

The only implementation for Scala I know of is in ScalaZ . 我知道的唯一Scala实现是在ScalaZ中

By such name of method as modify only it's easy to identify your ComplexModel as a mutator object, which means that it changes some state. 通过仅modify方法的名称,很容易将您的ComplexModel识别为modify器对象,这意味着它会更改某些状态。 That only implies that this kind of object has nothing to do with functional programming and trying to make it immutable just because someone with questionable knowledge told you that everything in Scala should be immutable will simply be a mistake. 这仅意味着此类对象与函数式编程无关,并试图使其变得不可变,只是因为某个知识渊博的人告诉您,Scala中的所有内容都应当不可变,这只是一个错误。

Now you could modify your api so that this ComplexModel operated on immutable data, and I btw think you should, but you definitely must not try to convert this ComplexModel into immutable itself. 现在您可以修改您的api,以便此ComplexModel对不可变数据进行操作,我想您应该这样做,但您绝对不能尝试将此ComplexModel转换为不可变本身。

Immutability is merely a useful tool, not dogma. 不变性只是有用的工具,而不是教条。 Situations will arise where the cost and inconvenience of immutability outweigh its usefulness. 出现不可变性的代价和不便超过其用途的情况。

The size of a ComplexModel may make it so that creating a modified copy is sufficiently expensive in terms of memory and/or CPU that a mutable model is more practical. ComplexModel的大小可能会使得在内存和/或CPU方面创建修改后的副本非常昂贵,因此可变模型更为实用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM