В Ruby существует несколько методов для сравнения объектов, и понимание различий между ними критически важно для корректной работы с объектами. Рассмотрим ключевые отличия между оператором равенства ==
и методом идентичности equal?
.
a = 5
b = 5.0
c = 5
puts a == b # => true (значения равны)
puts a.equal?(b) # => false (разные объекты)
puts a.equal?(c) # => true для небольших чисел (оптимизация Ruby)
str1 = "hello"
str2 = "hello"
str3 = str1
puts str1 == str2 # => true
puts str1.equal?(str2) # => false
puts str1.equal?(str3) # => true
# Для символов и небольших целых чисел Ruby использует оптимизацию
:symbol.equal?(:symbol) # => true
100.equal?(100) # => true
class Product
attr_reader :id
def initialize(id)
@id = id
end
def ==(other)
other.is_a?(Product) && id == other.id
end
end
p1 = Product.new(1)
p2 = Product.new(1)
p3 = p1
puts p1 == p2 # => true (сравнение по id)
puts p1.equal?(p2) # => false
puts p1.equal?(p3) # => true
Третий важный метод сравнения - eql?
:
==
5 == 5.0 # => true
5.eql?(5.0) # => false (разные типы)
Ситуация | Рекомендуемый метод |
---|---|
Сравнение значений | == |
Проверка идентичности | equal? |
Ключи в хэшах | eql? |
Сравнение с nil | nil? |
obj = nil
puts obj == nil # => true
puts obj.equal?(nil) # => true
puts obj.nil? # => true (предпочтительный способ)
arr1 = [1, 2]
arr2 = [1, 2]
puts arr1 == arr2 # => true
puts arr1.equal?(arr2) # => false
Вы можете переопределить ==
в своем классе, но equal?
переопределить нельзя:
class Book
attr_reader :isbn
def initialize(isbn)
@isbn = isbn
end
def ==(other)
other.is_a?(Book) && isbn == other.isbn
end
end
b1 = Book.new("123")
b2 = Book.new("123")
puts b1 == b2 # => true
puts b1.equal?(b2) # => false
Основные различия между методами сравнения:
==
- проверяет равенство значений (может быть переопределен)equal?
- проверяет идентичность объектов (не переопределяется)eql?
- используется для хэшей, учитывает тип объектовПравила выбора метода:
==
equal?
eql?
nil?
Понимание этих различий помогает избежать тонких багов при работе с объектами в Ruby.