2012-07-02 54 views
5

考慮下面的記錄:爲TEqualityComparer.Construct編寫散列函數的規範方法是什麼?

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

實際需要的哈希值,在您的情況?否則,我認爲返回的值不會被使用,所以它可以是任何東西,甚至是像1這樣的字面值。還是我在這裏錯了? –

+0

@Rudy不需要散列值。我可以返回一個真實的常數。或者引發'EMethodNotImplemented'異常。但我很好奇如何做對。 –

+0

啊,好吧。好奇心似乎對貓有點不好,但是。 ;-) –

回答

6

有關重寫hashCode的Effective Java (by Joshua Bloch)部分可能會有用。它顯示了對象(或記錄)的各個部分如何組合起來以有效地構造一個hashCode。

良好散列函數趨向於產生不相等的 對象不相等的散列碼。這正是 hashCode合約的第三條規定的含義。理想情況下,散列函數應該在所有 可能的散列值中統一分配任何不合理實例的合理集合。實現這一理想可能非常困難。 幸運的是,實現一個合理的近似值並不困難。這裏 是一個簡單的食譜:

  1. 存儲一些常非零值,比如說17,在被稱爲resultint變量。
  2. 對於您的對象中的每個顯著場f(每個字段的equals方法考慮進去,這是),做到以下幾點:

    一個。計算int哈希碼c該字段:..... 細節省略 ....

    b。將步驟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; 
相關問題