5

考虑以下记录:

TMyRecord = record
  b: Boolean;
  // 3 bytes of padding in here with default record alignment settings
  i: Integer;
end;

我希望实施IEqualityComparer<TMyRecord>. 为此,我想调用TEqualityComparer<TMyRecord>.Construct. 这需要提供一个TEqualityComparison<TMyRecord>对我没有问题的。

但是,Construct也需要一个THasher<TMyRecord>,我想知道实现它的规范方法。该函数需要具有以下形式:

function MyRecordHasher(const Value: TMyRecord): Integer;
begin
  Result := ???
end;

我希望我需要调用BobJenkinsHash记录值的两个字段,然后以某种方式将它们组合起来。这是正确的方法,我应该如何结合它们?

我不使用的原因TEqualityComparison<TMyRecord>.Default是它使用了CompareMem,因此由于记录的填充而将是不正确的。

4

1 回答 1

6

关于覆盖 hashCode的Effective Java(作者 Joshua Bloch)部分可能很有用。它展示了如何组合对象(或记录)的各个部分以有效地构造 hashCode。

一个好的散列函数往往会为不相等的对象产生不相等的散列码。这正是 hashCode 合约第三条的含义。理想情况下,散列函数应该在所有可能的散列值上均匀分布任何合理的不相等实例集合。实现这一理想可能非常困难。幸运的是,实现一个公平的近似并不难。这是一个简单的食谱:

  1. int在名为 的变量中存储一些恒定的非零值,例如 17 result
  2. 对于f对象中的每个重要字段(即 equals 方法考虑的每个字段),请执行以下操作:

    一个。计算字段的int哈希码c:.....细节省略....

    湾。将步骤 a 中计算的哈希码 c 合并到结果中,如下所示:result = 37*result + c;

  3. 返回result

  4. 编写完hashCode方法后,问问自己相等的实例是否具有相等的哈希码。如果没有,找出原因并解决问题。

这可以翻译成Delphi代码如下:

{$IFOPT Q+}
  {$DEFINE OverflowChecksEnabled}
  {$Q-}
{$ENDIF}
function CombinedHash(const Values: array of Integer): Integer;
var
  Value: Integer;
begin
  Result := 17;
  for Value in Values do begin
    Result := Result*37 + Value;
  end;
end;
{$IFDEF OverflowChecksEnabled}
  {$Q+}
{$ENDIF}

然后,这允许实现MyRecordHasher

function MyRecordHasher(const Value: TMyRecord): Integer;
begin
  Result := CombinedHash([IfThen(Value.b, 0, 1), Value.i]);
end;
于 2012-07-02T13:58:46.963 回答