=== vs. == в Ruby
В Ruby, в чем разница между == и ===? RDoc говорит
Case Equality - для класса Object, фактически то же самое, что вызов # ==, но обычно переопределяется потомками, чтобы обеспечить содержательную семантику в операторах case.
Является #==
такой же как ==
? И не могли бы вы привести пример, когда / как это используется в кейсах?
3 ответа
Два действительно не имеют ничего общего друг с другом. Особенно, #==
является оператором равенства и #===
не имеет ничего общего с равенством. Лично я считаю весьма прискорбным, что #===
выглядит так похоже на #==
, использует знак равенства и часто называется оператором равенства случаев, операторомтройного равенства или оператором трехзначностей, когда он действительно не имеет ничего общего с равенством.
Я звоню #===
оператор подстановки дел (это лучшее, что я мог придумать, я открыт для предложений, особенно от носителей английского языка).
Лучший способ описать a === b
это "если у меня есть ящик с надписью a
имеет ли смысл ставить b
в этом?"
Так, например, Module#===
проверяет ли b.is_a?(a)
, Если у вас есть Integer === 2
имеет ли смысл ставить 2
в коробке с надписью Integer
? Да, это так. Как насчет Integer === 'hello'
? Очевидно нет.
Другой пример Regexp#===
, Это тесты на совпадение. Есть ли смысл ставить 'hello'
в коробке с надписью /el+/
? Да, это так.
Для коллекций, таких как диапазоны, Range#===
определяется как тест членства: имеет смысл поместить элемент в поле, помеченное коллекцией, если этот элемент находится в коллекции.
Итак, вот что #===
has: проверяет, может ли аргумент быть отнесен к получателю.
Какое это имеет отношение к case
выражения? Просто:
case foo
when bar
baz
end
такой же как
if bar === foo
baz
end
Да, по #==
документы означают "метод экземпляра" ==
текущего объекта ".
===
используется в утверждениях case как таковых:
case obj
when x
foo
when y
bar
end
Такой же как
if x === obj
foo
elsif y === obj
bar
end
Некоторые классы, которые определяют свои собственные ===
Диапазон (действовать как include?
), Класс (вести себя как obj.is_a?(klass)
) а также Regexp
(вести себя как =~
кроме возврата логического). Некоторые классы, которые не определяют свои собственные ===
числовые классы и String.
Так
case x
when 0
puts "Lots"
when Numeric
puts(100.0 / x)
when /^\d+$/
puts(100.0 / x.to_f)
default
raise ArgumentError, "x is not a number or numeric string"
end
такой же как
if 0 == x
puts "Lots"
elsif x.is_a? Numeric
puts(100.0 / x)
elsif x =~ /^\d+$/
puts(100.0 / x.to_f)
else
raise ArgumentError, "x is not a number or numeric string"
end
Интересный факт, ===
также используется для сопоставления исключений в rescue
Вот пример
class Example
def self.===(exception)
puts "Triple equals has been called."
true
end
end
raise rescue Example
# => prints "Triple equals has been called."
# => no exception raised
Это используется для соответствия системным ошибкам.
SystemCallError.===
было определено, чтобы возвращать истину, когда два имеют одинаковое значение errno. С помощью этого системного вызова ошибки с тем же номером ошибки, такие как Errno::EAGAIN
а также Errno::EWOULDBLOCK
, оба могут быть спасены, перечислив только один из них.