Подтвердить что ты не робот

Какой правильный способ реализации равенства в рубине

Для простого структуроподобного класса:

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 в этой ситуации?

4b9b3361

Ответ 1

Чтобы упростить операции сравнения для объектов с более чем одной переменной состояния, создайте метод, который возвращает все состояние объекта в виде массива. Затем просто сравните два состояния:

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

Чтобы проверить равномерность всех ваших переменных экземпляра:

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

Обычно с оператором ==.

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