F#记录的GetHashCode()是如何实现的?

How is GetHashCode() of F# record implemented?

我很难在 https://github.com/fsharp/fsharp

上找到它

这非常重要,因为我需要确保尽可能少的碰撞。

好吧,我可以告诉你,它不会提供尽可能少的碰撞。您可能想要覆盖 GetHashCode。有些人抱怨它不符合他们的散列需求,但为了向后兼容,它不能合理地改变。如果出于检查冲突哈希的性能考虑,这对您来说是一个严重的问题,我会在 github visual fsharp 存储库中添加一个问题。

更新,来源: github.com/fsharp/fslang-suggestions/issues/366 github.com/fsharp/fsharp/issues/343 github.com/Microsoft/visualfsharp/issues/1838

正如 VoroniPotato 所提到的,您可能想自己覆盖 GetHashCode,但 GetHashCode 的默认实现如下所示。假设fields是记录中字段值的列表,那么做如下步骤:

  1. 从初始值 0 开始。

  2. 然后对于字段中的每个元素,从最后一个定义的元素开始(即给定记录类型 {a: int; b: string} 我们从 b 开始),执行以下操作:

    0x9e3779b9 + fields.[i].GetHashCode() + (value <<< 6) + (value >>> 2),其中值是算法上一次迭代的值。我们假设 fields.[i] 不为空,否则它的哈希值只是设置为 0.

  3. 对所有字段重复步骤 2。

您可以在 mkRecdHashWithComparer and mkAddToHashAcc 的代码中的源代码中看到这一点。

{a: int; b: string}的简单示例记录,反编译后的GetHashCode方法是这样的:

[CompilerGenerated]
public sealed override int GetHashCode(IEqualityComparer comp)
{
    if (this != null)
    {
        int num = 0;
        num = -1640531527 + ((b@?.GetHashCode() ?? 0) + ((num << 6) + (num >> 2)));
        return -1640531527 + (a@ + ((num << 6) + (num >> 2)));
    }
    return 0;
}