【问题标题】:Why F#'s idiomatic dictionary collection (Map<K,V>) needs the type K to implement comparable while C#'s Dictionary<K,V> doesn't?为什么 F# 的惯用字典集合 (Map<K,V>) 需要类型 K 来实现可比较,而 C# 的 Dictionary<K,V> 不需要?
【发布时间】:2020-05-22 08:05:25
【问题描述】:

我知道这个问题和我前段时间问的这个问题很相似:Why F#'s default set collection is sorted while C#'s isn't?

但是,我想确认一下在这种情况下给出的原因是否相同?我想知道是否有一个不可变的Map 在 F# 中的实现,由某人编写,它不那么严格并且不需要 K 具有可比性?我很乐意使用它,因为我不太关心性能。

【问题讨论】:

  • System.Collections.Immutable.ImmutableDictionary 没有键约束

标签: dictionary f# hashtable c#-to-f#


【解决方案1】:

为什么 F# 的惯用字典集合 Map&lt;K,V&gt; 需要类型 K 实现可比较而 C# 的 Dictionary&lt;K,V&gt; 没有?

F# Map&lt;Key, Value&gt; 要求键是可比较的,因为 map 是 implemented as a tree structure (您必须根据比较结果决定去哪个子树)。 C# Dictionary&lt;Key, Value&gt; 被实现为一个链表桶。您通过键的哈希码获得一个桶,然后迭代列表,直到您(不)找到相等的键。在这两种数据结构中,都会比较键。唯一的区别是对于字典相等比较就足够了。

那么,问题是为什么 F# Map 具有 显式 比较约束,而 C# Dictionary 具有 隐式 相等要求?

让我们从 C# 开始。如果字典有 IEquatable 键约束会怎样?好吧,您将必须为用作字典键的每个自定义数据类型手动实现此接口。但是如果你想要不同的平等实现呢?例如。在某些字典中,您希望您的密钥字符串不区分大小写。当然,您可以传递IEqualityComparer 实现以用于键比较(不仅是字典,还可以在需要比较的任何地方)。但是,如果使用外部比较器,为什么还要强制 key 是可比较的呢?请注意,如果您不向字典传递任何内容,则始终使用默认比较器。默认比较器检查 key 是否实现 IComparable 并使用该实现。

为什么 F# 对关键数据类型有明确的可比较约束?因为此约束不会强制您手动实现IComparable 用于每个用作映射键的自定义数据类型。 C# 和 F# 类型系统之间的一大区别是 F# 类型在默认情况下具有可比性和相等性。 F# 编译器生成 IComparableIComparable&lt;T&gt;IStructuralComparable 实现,除非您使用 NoComparison 属性显式标记类型。因此,当您使用 F# 数据类型时,此约束不会强制您编写任何额外的代码。

使用比较/相等约束的另一个好处 - F# 对实现比较或相等的类型(=、=、=、max、min)有许多预定义的通用操作。这使得具有通用可比较/相等类型的代码更具可读性。

【讨论】:

  • 简单地说,.NET 字典类型实际上是一组数组而不是链表:github.com/dotnet/runtime/blob/…
  • 是和否 :) 这是一个存储在数组中以进行优化的链表 - 检查 Entry 结构 - 它有 next 这是下一项的索引
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-21
  • 2019-10-10
  • 2011-04-21
  • 2018-11-23
  • 2019-07-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多