考虑以下记录:
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
,因此会因记录的填充而不正确。
答案 0 :(得分:6)
关于覆盖hashCode的Effective Java (by Joshua Bloch)部分可能很有用。它显示了如何组合对象(或记录)的各个部分以有效地构造hashCode。
良好的散列函数往往会产生不等的哈希码 对象。这正是第三条规定的含义 hashCode合约。理想情况下,散列函数应该分配任何 合理地收集所有不平等的实例 可能的哈希值。实现这一理想可能非常困难。 幸运的是,实现公平的近似并不太难。这里 是一个简单的食谱:
- 将一些常量非零值(例如17)存储在名为
int
的{{1}}变量中。对于对象中的每个重要字段
result
(通过equals方法考虑的每个字段,即),请执行以下操作:一个。为字段计算
f
哈希码int
:..... 详细信息省略 ....湾将步骤a中计算的哈希码c组合成 结果如下:
c
返回
result = 37*result + c;
。- 醇>
完成
result
方法的编写后,请问自己,相等的实例是否具有相同的哈希码。如果没有,找出原因 并解决问题。
这可以翻译成Delphi代码如下:
hashCode
这样就可以实现{$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