Переопределить == оператор в Ruby
Согласно документам, Array.include? использует сравнение == для объектов. Я пришел из Java, где такие вещи (обычно) делаются с помощью .equals(), который легко переопределить для конкретного объекта.
Как я могу переопределить == в Ruby, чтобы я мог указать поведение Array.include? для моего конкретного объекта?
Большое спасибо.
3 ответа
В рубине ==
это просто метод (с некоторым синтаксическим сахаром на вершине, что позволяет писать foo == bar
вместо foo.==(bar)
) и вы переопределите ==
как и любой другой метод:
class MyClass
def ==(other_object)
# return true if self is equal to other_object, false otherwise
end
end
Это не сильно отличается от переопределения равенства в java и, к сожалению, нигде не соблюдается так строго, как должно быть в экосистеме Ruby. Нередко можно найти библиотеки, которые нарушают равенство и ведут себя непредсказуемо, например, при использовании в коллекциях.
- При переопределении также переопределяйте
hash
; на практике это проще реализовать в Ruby, потому что вы можете делегировать Array или Set для вычисления хеша:[field1, field2].hash
- Пожалуйста убедитесь
eql?
также правильно переопределяется, чтобы гарантировать правильное поведение экземпляров при использовании в качестве ключей в Hash. - Переопределенное равенство должно быть рефлексивным, т.е. a == a должно быть истинным; вы должны использовать
equal?
чтобы проверить, является ли это одним и тем же объектом, а затем сократить проверку на равенство, если это так, для существенного повышения производительности. - Замещенное равенство должно быть симметричным, т. е. если a == b, то b == a также должно быть истинным.
- Замещенное равенство должно быть транзитивным, т. е. если a == b и b == c, то a == c также должно быть истинным.
- Переопределенное равенство должно гарантировать либо
true
илиfalse
как возвращаемое значение. Он никогда не может вызвать исключение. - Простая вещь, за которой нужно следить, это количество спецификаций, которые вы пишете каждый раз, когда переопределяете; вам нужно будет добавить по крайней мере от 5 до 7 спецификаций помимо тех, которые вы могли бы добавить, чтобы покрыть граничные условия для логики равенства.
- Как я сказал в начале, остерегайтесь переопределения
==
при работе с библиотеками и фреймворками. Распространенным случаем является равенство экземпляров ActiveRecord, когда вы можете сломать Rails, если не будете вдумчивы.
Как описано выше, == - это метод Ruby, который можно переопределить. Вы просто запишете условие равенства.
class Person
attr_reader :name, :gender, :social_id
attr_accessor :age
def initialize(name, age, gender, social_id)
self.name = name
self.age = age.to_i
self.gender = gender
self.social_id = social_id
def ==(other)
social_id == other.social_id
Вам больше не нужно переопределять другие методы