2012-08-23 21 views
6

看看這個簡單的類我建設爲基數,以存儲字符串匹配算法的結果:爲什麼這些對象默認在D中不相等?

/** Match of a single pattern in full to a single text. */ 
class Match { 
    uint Tpos; 

    this(in uint Tpos) { this.Tpos = Tpos; } 

    override string toString() { 
     return text("Match: [email protected]",Tpos); 
    } 
} 

這就是事情變得怪異:

auto m1 = new Match(1), m2 = new Match(1); 
writeln(m1.toHash()); 
writeln(m2.toHash()); 
writeln(m1 == m2); 

打印

4464528 
4464512 
false 

我沒有看到爲什麼這兩個對象默認不應該被認爲是相同的。我想我可以寫一個自定義toHash()opEquals()函數,但這似乎是矯枉過正。根據Andrei Alexandrescu的D編程語言book(偉大的書!),「默認情況下,散列是通過使用對象的按位表示來計算的。」那裏有任何想法?

回答

8

從源代碼(DMD2/src目錄/ druntime/src目錄/ object_.d):

class Object 
{ 
/* snip */ 
    /** 
    * Compute hash function for Object. 
    */ 
    hash_t toHash() @trusted nothrow 
    { 
     // BUG: this prevents a compacting GC from working, needs to be fixed 
     return cast(hash_t)cast(void*)this; 
    } 
/* snip */ 
    /** 
    * Returns !=0 if this object does have the same contents as obj. 
    */ 
    equals_t opEquals(Object o) 
    { 
     return this is o; 
    } 
} 

因此,答案很簡單,就是代碼編寫的方式 - 他們做身份檢查而不是內容檢查。這是爲什麼呢?我不知道,但我的猜測是,原本寫作很簡單,而且工作得很好,以至於沒有人願意回過頭來改變它。

在新聞組,還有的是從對象完全消除這些功能進行了一些討論,所以如果你想==在你的類,你必須實現的東西。但是,談到這樣的事情時,新聞組談話成爲行動所花費的時間通常很長。他們可能會改變主意。

使用當前並可能在可預見的未來階級平等的,最好的辦法是寫在課堂上你自己的opEquals方法。

+0

感謝您的源代碼和洞察力。我沒有意識到==相比於默認身份。無論如何,我最終將其重寫爲結構體,因爲大多數情況下我都希望通過值來複制對象。 – denine99

4

答案很簡單:在默認情況下,opEquals的對象物體的地址進行比較。你需要必須覆蓋它,如果你想要價值語義(或只使用struct)。

旁註:您使用的in不正確。 inscope const的簡稱,其中scope的意思是「我不會在我的堆棧框架之外逃脫該參數」(通過將它分配給類字段)。不幸的是,編譯器還沒有強制執行,這就是爲什麼你沒有得到一個錯誤。

+2

我不知道,但我覺得範圍有關引用(或指針)逃逸,這是合法的範圍的純值參數複製到外部變量。 – cybevnm

+3

函數參數的'scope'(因此'in')應該防止與該參數相關聯的引用轉義該函數(這將包括將其分配給成員變量) - 雖然確實檢查是無法正確實現的馬上。但是,在這種特殊情況下,無論如何,這都是好事,因爲參數是一個「uint」,它是一個值類型。 「範圍」對於值類型沒有實際意義 - 只有引用類型 - 因爲參數被複制,所以沒有提及甚至是轉義。 –

+0

我想'in'不是這裏最好的修飾語; 'const'是一個更好的選擇,雖然有了這麼短的構造函數,但使用什麼限定符可能並不重要。感謝有關'範圍'的信息。 – denine99

相關問題