==, equal?, eql?, === у Ruby: що перевіряють і коли використовувати

Обкладинка допису: ==, equal?, eql?, === у Ruby: що перевіряють і коли використовувати
У Ruby існує кілька способів порівняння. Вони схожі на перший погляд, але працюють зовсім по-різному.

== (перевірка рівності значень)

  • Перевіряє, чи мають об’єкти однаковий зміст.
  • Часто перевизначається у класах (String, Array, Hash), щоб порівнювати значення, а не ідентичність.
a = "hello"
b = "hello"

a == b        # => true
a.equal?(b)   # => false
== питає: "Чи однаковий зміст у цих об’єктів?"

equal? (перевірка ідентичності об’єктів)

  • Перевіряє, чи це один і той самий об’єкт у пам’яті.
  • Не перевизначається у класах, завжди порівнює об’єктні id.
a = "hello"
b = "hello"
c = a

a.equal?(b)  # => false
a.equal?(c)  # => true
Тут для розуміння всього цього діла, треба знати що таке об'єкт в Ruby.

eql? (сувора перевірка рівності для хешів та чисел)

  • Перевіряє значення і тип.
  • В основному використовується в хешах для ключів.
1 == 1.0     # => true
1.eql?(1.0)  # => false, бо різні класи (Integer vs Float)
eql? більш суворий, ніж ==.

=== (case-match оператор)

  • Використовується переважно у конструкції case (розберемо це нижче).
  • Для різних класів поводиться по-різному:
    • У класів (String, Integer) - перевіряє, чи об’єкт належить до класу (is_a?).
    • У регулярних виразах - перевіряє, чи рядок підпадає під паттерн.
    • У Range - чи входить об’єкт у діапазон.
case 5
when 1..10
  "В діапазоні"   # => "В діапазоні"
end

String === "hello"  # => true
/ell/ === "hello"   # => true
Розглянемо трохи детальніше приклад з case. Як працює case … when у Ruby?
Синтаксис:
case об’єкт
when зразок1
  код1
when зразок2
  код2
else
  код_за_замовчуванням
end
Що відбувається під капотом
Ruby робить приблизно так:
if зразок1 === об’єкт
  код1
elsif зразок2 === об’єкт
  код2
else
  код_за_замовчуванням
end
Тобто when автоматично використовує === для порівняння з case-значенням. 
Далі приклади для різних типів
Діапазон (Range)
case 5
when 1..10
  "В діапазоні"
else
  "Поза діапазоном"
end
# => "В діапазоні"
Працює так, ніби Ruby виконує (це псевдо код):
(1..10) === 5  # => true
Але важливо зазначити, що звичайне використання === на числах чи інших типах не обов’язково працює так само:
10 === (1..20)   # => false
10 == (1..20)    # => false
(1..20) == 10    # => false
Тут Range#=== перевіряє, чи входить число у діапазон.
Клас
case "hello"
when String
  "Це рядок"
when Integer
  "Це число"
end
# => "Це рядок"
Ruby виконує:
String === "hello"   # => true
Integer === "hello"  # => false
Для класів === — це скорочення для obj.is_a?(Клас).
c) Регулярний вираз
case "hello"
when /ell/
  "Збіг з паттерном"
else
  "Немає збігу"
end
# => "Збіг з паттерном"
Під капотом:
/ell/ === "hello"   # => true
Для Regexp === перевіряє, чи рядок відповідає паттерну.
Ми відійшли трохи від теми === і перейшли до case (бо там === під капотом). Такий простий оператор, але робить різні штуки.
Щоб простіше запам'ятати:
  • case x; when y - це не x == y, а y === x.
  • === працює по-різному залежно від типу y:
    • Class -> is_a?
    • Range -> include?
    • Regexp -> =~ (збіг рядка)
Це дозволяє дуже гнучко писати умови.

Цей допис поки що не має жодних доповнень від автора/ки.

Як працює self, protected і private (Ruby)
28 жовт., 13:52

Як працює self, protected і private (Ruby)

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Цілочисельне ділення у Ruby: чому 6 / 4 дорівнює 1
28 жовт., 14:10

Цілочисельне ділення у Ruby: чому 6 / 4 дорівнює 1

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
28 жовт., 14:42

Як працює &:to_s у Ruby і що таке Symbol#to_proc

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Що таке Proc і Lambda в Ruby?
28 жовт., 15:57

Що таке Proc і Lambda в Ruby?

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Що відбувається, якщо викликати [1, 2, 3].map(&Person)
29 жовт., 17:54

Що відбувається, якщо викликати [1, 2, 3].map(&Person)

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Singleton class (eigenclass) у Ruby: що це і навіщо потрібно
29 жовт., 18:29

Singleton class (eigenclass) у Ruby: що це і навіщо потрібно

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Include, Extend, Prepend у Ruby: як вони працюють і в чому різниця
29 жовт., 21:20

Include, Extend, Prepend у Ruby: як вони працюють і в чому різниця

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
module_function у Ruby: коли методи модуля доступні як модульні та як функції
29 жовт., 21:53

module_function у Ruby: коли методи модуля доступні як модульні та як функції

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Що таке memoization в Ruby?
30 жовт., 10:17

Що таке memoization в Ruby?

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
is_a?, kind_of?, instance_of? — як Ruby перевіряє тип об’єкта?
30 жовт., 19:55

is_a?, kind_of?, instance_of? — як Ruby перевіряє тип об’єкта?

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
&& vs and — різниця в Ruby, яка може зламати ваш код
30 жовт., 20:23

&& vs and — різниця в Ruby, яка може зламати ваш код

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska
Змінні у Ruby: @, @@ та class instance variable
30 жовт., 20:54

Змінні у Ruby: @, @@ та class instance variable

Нотатки про Ruby та RoR
Нотатки про Ruby та RoR@kovbaska