2009-12-19 96 views
38

平等對於一個簡單的結構,例如類的正確方法:什麼是在Ruby中實現

class Tiger 
    attr_accessor :name, :num_stripes 
end 

什麼要正確實現平等,以確保=====eql?等工作,正確的方法使在很好的集合類遊戲的情況下,哈希等

編輯

而且,什麼是實現平等,當你想基於比較的好方法沒有暴露在課堂外的狀態?例如:

class Lady 
    attr_accessor :name 

    def initialize(age) 
    @age = age 
    end 
end 

在這裏,我想我的平等法取@age考慮,但這位女士沒有她的年齡暴露給客戶。在這種情況下,我需要使用instance_variable_get嗎?

+0

[這是一個很好的書面記錄比較確定對象平等的來龍去脈(http://www.skorks.com/2009/09/ruby​​-equality-and-object-comparison /) – ennuikiller 2009-12-19 01:27:03

回答

61

要簡化具有多個狀態變量的對象的比較運算符,請創建一個將所有對象的狀態作爲數組返回的方法。然後,只需比較兩種狀態:

class Thing 

    def initialize(a, b, c) 
    @a = a 
    @b = b 
    @c = c 
    end 

    def ==(o) 
    o.class == self.class && o.state == state 
    end 

    protected 

    def state 
    [@a, @b, @c] 
    end 

end 

p Thing.new(1, 2, 3) == Thing.new(1, 2, 3) # => true 
p Thing.new(1, 2, 3) == Thing.new(1, 2, 4) # => false 

另外,如果你希望你的類的實例是可用作爲哈希鍵,然後補充:

alias_method :eql?, :== 

    def hash 
    state.hash 
    end 

這些都需要公開。

+2

我真的很喜歡這種比較對象的技巧,通過委託給狀態數組進行比較。 – 2010-01-06 23:29:39

1

通常與==運算符。

def == (other) 
    if other.class == self.class 
    @name == other.name && @num_stripes == other.num_stripes 
    else 
    false 
    end 
end 
+0

謝謝。不過,我認爲如果你只定義了==,那麼類的實例在哈希和集合中將不會像預期的那樣運行。 – 2009-12-20 18:51:21

+0

此外,我認爲/ ==不應該檢查類型相等(如你的例子所做的那樣)。那是什麼eql?應該這樣做。這可能是錯的。 – 2009-12-21 01:34:35

+0

只有你讓它變化,皮特纔會有所不同。最後,我檢查了'true == true'(和'1 + 1 == 2')仍然返回'true' ... – 2009-12-21 17:45:12

12

一次測試所有的實例變量平等:

def ==(other) 
    other.class == self.class && other.state == self.state 
end 

def state 
    self.instance_variables.map { |variable| self.instance_variable_get variable } 
end 
+3

這真的是更好,因爲它確保你不會意外地遺漏任何變量。現在,自動使用每個實例變量也可能會有一些意想不到的後果,但是我不確定,直到有一天我都會感到驚訝。 – WattsInABox 2015-01-22 02:18:32

+0

確實如此,您可以添加可選參數,例如對於這些特定情況的「僅」或「除外」。 – jvenezia 2015-01-22 09:16:19