我知道这个问题和我前段时间问的这个问题很相似。为什么F#的默认集合是排序的,而C#的不是?
但是,我想确认一下,那里给出的原因是否和这种情况一样?而且我想知道是否有一种实现不可变的 Map
在F#中,有谁写的,不那么严格,不需要K来比较?我很乐意用,因为我不那么在乎性能。
为什么F#的成语字典集合要排序
Map<K,V>
需要类型K来实现比较,而C#的Dictionary<K,V>
没有?
F# Map<Key, Value>
要求键是可比的,因为map是 以树状结构实现 (你必须根据比较结果决定去哪个子树)。C# Dictionary<Key, Value>
被实现为一个链接列表的桶。你通过键的哈希码得到一个桶,然后迭代列表,直到你(不)找到相等的键。在这两种数据结构中,键都是比较的。唯一不同的是,对于字典的平等比较就足够了。
所以,问题是为什么F# Map
有 明确 比较约束,但C# Dictionary
有 隐性 平等要求?
让我们从C#开始。如果字典有一个叫 IEquatable
关键约束?那么,你会 必须手动实现这个接口 对于每个用作字典键的自定义数据类型。但是如果你想要不同的平等性实现呢?例如,在一些字典中,你希望你的键字符串不区分大小写。当然,你可以通过 IEqualityComparer
的实现来进行键的比较(不仅是与字典的比较,而是在任何需要比较的地方)。但是,如果外部比较器被使用,为什么还要强制要求键比较呢?请注意,如果你不向字典传递任何东西,总会有一个默认比较器被使用。缺省比较器检查 key 是否实现了 IComparable
并使用该实现。
那为什么F#对关键数据类型有一个明确的可比较约束呢?因为这个约束条件 不会强制您手动执行 IComparable
对于每一个用作映射键的自定义数据类型。C#和F#类型系统的一个很大的区别是,F#类型默认是可比较和等价的。F#编译器会生成 IComparable
, IComparable<T>
和 IStructuralComparable
实现,除非你明确地用 NoComparison
属性。所以,当你使用F#数据类型时,这个约束并不强制你写任何额外的代码。
使用comparisonequality约束还有一个好处--F#对实现比较或平等的类型有许多预定义的通用操作(=,<,<=,>=,=,max,min)。这使得使用通用comparableequatable类型的代码更加可读。