我正在让应用程序中的大多数基本类型都是不可变的。但集合类型也应该是不可变的吗?对我来说,这似乎是一个巨大的开销,除非我有所遗漏。
我说的是用于保存 Point3 值等的集合,可以在不同时间添加。所以如果集合中有 1 百万个值,并且您需要删除其中一个值,那么您将不得不重新创建相同的集合,对吧?
我正在让应用程序中的大多数基本类型都是不可变的。但集合类型也应该是不可变的吗?对我来说,这似乎是一个巨大的开销,除非我有所遗漏。
我说的是用于保存 Point3 值等的集合,可以在不同时间添加。所以如果集合中有 1 百万个值,并且您需要删除其中一个值,那么您将不得不重新创建相同的集合,对吧?
Eric Lippert在C#的不可变性系列中,如果您阅读完整个系列,他会实现几个不同的不可变集合:
不可变集合非常好,特别是如果您的应用程序已经利用了不可变类型或语义。
.NET刚刚发布了他们的第一个不可变集合,我建议您尝试一下。
myList.WidthAddedItem("George");
的人更可能认识到正在创建和丢弃一个新的修改后的列表,而不是看到 myList.Add("George")
的人),但除此之外它们听起来非常好。顺便说一下,关于文章的一个问题:ReadOnlyCollection<T>
提供了一个接口也可以保证(对于正确的实现)但所提到的接口没有的承诺:引用不能用于修改集合。 - supercat我最喜欢使用集合的技巧就是从不在不同对象之间传递它们。如果它们只存在于一个对象内部,那么使它们不可变基本上是无关紧要的(只要包含它们的对象不改变它们,它们就不会改变)。
通常你的集合代表着某些东西,对吧?它是一组狗或一组发票...
通常有一些你可以对一组狗做的事情(放牧?绝育?),或者一组发票可以做的事情(付款?)。几乎总会有一些操作应用于整个对象列表--这些操作具有超出单个发票.pay()功能的功能(例如,确保最重要的发票首先得到支付),如果没有一个包装器来包装你的集合,那么真的没有地方可以放置这些操作。
同时,通常将几个变量与您的集合相关联也是有意义的--再次,如果没有包装器,您总是会将这些变量放在一些奇怪的不自然的位置。
起初可能会感觉很奇怪,但在评判之前请尝试几次。
如果您只是从开头或结尾添加/删除,您可能可以作弊 - 但通常情况下,是的:这意味着您需要为每个更改创建一个新的集合。
所以:您需要有效地更改集合吗?如果是这样,并且考虑到它们的大小:我会倾向于查看同步访问(而不是使它们完全不可变)。查看lock
(又名Monitor
)。
这取决于你的程序编写/设计的风格。
当你使用函数式编程风格时,不可变集合才有意义(命令式设计的程序不应该使用它们)。
就像在函数式语言中一样,你应该使用链表,可以每个元素以O(1)的时间复杂度构建(cons
),并从中进行函数式处理(递归,从列表构建新列表)。
当你的程序需要命令式集合(数组、向量/列表)时,请保持它们是可变的。
这完全取决于同时使用集合的人。字符串是不可变的,以防止出现两个线程同时尝试删除第一个字符等错误。
如果您有一个在构建后可以添加项目的集合,则它不是不可变的