kno*_*cte 4 f# dictionary hashtable c#-to-f#
我知道这个问题与我前一段时间问过的问题非常相似:为什么 F# 的默认集合集合是排序的,而 C# 的默认集合集合不是?
不过,我想确认一下,这里给出的原因是否与本案相同?我想知道 F# 中是否有一个由某人编写的不可变实现Map,它不那么严格并且不需要 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>和实现。因此,当您使用 F# 数据类型时,此约束不会强制您编写任何额外的代码。IStructuralComparableNoComparison
使用比较/相等约束的另一个好处 - F# 对实现比较或相等的类型有许多预定义的泛型操作(=、<、<=、>=、=、max、min)。这使得具有通用可比较/可等同类型的代码更具可读性。