2013-04-24 93 views
6

我在這裏做一個Ruby教程: http://rubymonk.com/learning/books/4-ruby-primer-ascent/chapters/45-more-classes/lessons/105-equality_of_objects比較對象等價於Ruby的

它說當我重載==運營商,我也應該重載eql?方法和散列方法,因爲他們是「快」。

但是,如果我用三種方法重載所有這三種方法,其中一個比另一個更快?

+0

相關:http://stackoverflow.com/questions/10257096/why-is-faster-than-eql – 2013-04-24 22:36:23

+0

@SemyonPerepelitsa:原來並不真正相關,但我很高興能夠回答這個棘手的問題: - ) – 2013-04-25 00:16:28

+0

感謝您回答! – 2013-04-25 00:34:06

回答

13

在大多數情況下,==eql?有同樣的結果。在某些情況下,eql?==更嚴格:

42.0 == 42 # => true 
42.0.eql?(42) # => false 

因此,如果您定義==你可能要定義eql?也(反之亦然)。

選擇Hash類將使用eql?來區分不同的密鑰,而不是==。這可能是==,介意你,但eql?更乾淨。

爲避免花費大量時間致電eql?,計算散列值時要求兩個對象eql?必須具有相同的散列值。該散列值的存儲,這使得未來的查找非常簡單:如果哈希代碼不匹配,則值不eql? ...

出於這個原因,你必須在一個合理的方式定義hash如果你定義eql?

請注意,計算散列值幾乎總是比與==eql?進行比較要貴。但是,一旦散列被計算出來,檢查散列匹配是非常快的。

因爲散列通常涉及非常多的比較,所以對每個鍵執行一次相對昂貴的散列計算,然後對每次查找執行一次。想象一下有10個條目的散列。在第一次查詢完成之前,構建它將涉及到10個對hash的調用。第一次查找將會相對較快:一次調用hash,隨後對哈希代碼進行非常有效的比較(實際上比這更快,因爲它們是「索引的」)。如果有一場比賽,我們仍然需要打電話給eql?以確保這是一場真正的比賽。實際上,兩個不是eql?的對象可能具有相同的散列。唯一的保證是兩個對象eql?必須具有相同的散列,但是兩個不同的對象也可以具有相同的散列。

如果您想要使用Array代替,則每次查找時可能需要10次調用eql?

對於什麼是值得的,我不認爲你鏈接到的Ruby引擎是如此清晰。它忽略了這樣一個事實,即計算hash可能是昂貴的,所以只有當它有意義時,即,當每個元素將被多次比較是一個很好的假設時纔會這樣做。此外,它自定義的eql?示例使用==來比較實例變量,這是一個恥辱。理想情況下,它將使用eql?作爲一致性,與數組爲==(如果其元素爲==)以及數組爲eql?(如果其元素爲eql?)相同。最後,它應該提到Struct,它爲你定義了體面的==,hasheql?

+0

中更加明確地感謝這裏的詳細解釋,這絕對有助於清除它 – Ricky 2013-04-24 23:32:24

3

例如, Array#hash說 -

具有相同內容的兩個數組將具有相同的哈希碼(並將使用eql?進行比較)。

Array#==說:

平等 - 兩個數組相等,如果它們包含相同數量的元素,並且如果每一個元素等於(根據對象#==)在other_ary的對應元素。

Array#eql?

返回true自我與他人是同一個對象,或者是具有相同內容的兩個陣列。

所以按照文件很清楚,eql?速度更快,因爲它使用hash值,與eql?。而#==做兩件事情 -

陣列的
  1. 長度和
  2. 每個元素相等測試。
+0

那麼爲什麼不比較使用==而不是eql?是否因爲eql使用比較快的哈希代碼?它不會在內部使用==來比較兩個哈希碼的等價性嗎? – Ricky 2013-04-24 21:21:43

+0

謝謝!這很有道理 – Ricky 2013-04-24 21:29:26

+2

這個答案是錯誤的:'eql?'不使用'hash'值,並且不會比'=='更快。 – 2013-04-24 21:47:10