2009-12-19 6 views
38

Para una sencilla clase de estructura similar:Cuál es la forma correcta para implementar la igualdad en rubí

class Tiger 
    attr_accessor :name, :num_stripes 
end 

¿cuál es la forma correcta de poner en práctica la igualdad correctamente, para asegurar que ==, ===, eql?, etc trabajo, y de manera que las instancias de la obra de teatro muy bien en conjuntos, hashes, etc.

EDITAR

Además, lo que es una buena manera de poner en práctica la igualdad cuando se desea comparar basada en estado que no está expuesto fuera de la clase? Por ejemplo:

class Lady 
    attr_accessor :name 

    def initialize(age) 
    @age = age 
    end 
end 

aquí me gustaría que mi método de la igualdad de tomar @age en cuenta, pero la señora no expone su edad a los clientes. ¿Tendría que usar instance_variable_get en esta situación?

+0

[Esta es una buena valoración crítica comparando los pros y contras de la definición de igualdad de objetos] (http://www.skorks.com/2009/09/ruby-equality-and-object-comparison /) – ennuikiller

Respuesta

61

Para simplificar operadores de comparación para los objetos con más de una variable de estado, crear un método que devuelve todos el estado del objeto como una matriz. A continuación, sólo comparar los dos estados:

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 

También, si quieres instancias de la clase para ser utilizable como una clave hash, a continuación, añadir:

alias_method :eql?, :== 

    def hash 
    state.hash 
    end 

estos deben ser públicos.

+2

Me gusta mucho este truco de comparar objetos usando al delegar la comparación con la matriz de estado. –

1

Generalmente con el operador ==.

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

Gracias. Sin embargo, creo que si solo defines ==, las instancias de la clase no se comportarán como se espera en hashes y sets. –

+0

Además, I/think/that == no se supone que verifique la igualdad de tipo (como lo está haciendo su ejemplo). Eso es lo que eql? se supone que debe hacer Podría estar equivocado en eso. –

+0

El comportamiento solo varía si lo haces variar, Pete. La última vez que verifiqué 'verdadero == verdadero' (y' 1 + 1 == 2') todavía devuelve 'verdadero' ... –

12

Para probar la igualdad de todos sus variables de instancia a la vez:

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

Esto realmente es mucho mejor porque garantiza que no omita accidentalmente ninguna variable. Ahora, también puede haber algunas consecuencias involuntarias al usar automáticamente cada variable de instancia, pero no estoy seguro y no lo sabré hasta que me sorprenda algún día. – WattsInABox

+0

Es cierto, puede agregar parámetros opcionales, como 'solo' o 'excepto' para esos casos particulares. – jvenezia

Cuestiones relacionadas