Если быть точным, a ||= b
означает "если a
не определено или является ложным (false
или nil
), установите a
в b
и оцените (т.е. верните) b
, в противном случае оцените a
".
Другие часто пытаются проиллюстрировать это, говоря, что a ||= b
эквивалентно a || a = b
или a = a || b
. Эти эквивалентности могут быть полезны для понимания концепции, но имейте в виду, что они не точны при любых условиях. Позвольте мне объяснить:
a ||= b
⇔ a || a = b
?
Поведение этих операторов отличается, когда a
является неопределенной локальной переменной. В этом случае a ||= b
установит a
на b
(и оценит b
), тогда как a || a = b
повысит NameError: undefined local variable or method 'a' for main:Object
.
a ||= b
⇔ a = a || b
?
Эквивалентность этих утверждений часто предполагается, поскольку аналогичная эквивалентность верна для других сокращенных операторов присваивания (т.е. +=
, -=
, *=
, /=
, %=
**=
, &=
, |=
, ^=
, <<=
и >>=
). Однако для ||=
поведение этих операторов может отличаться, когда a=
является методом объекта, а a
является правдивым. В этом случае a ||= b
ничего не будет делать (кроме оценки a
), тогда как a = a || b
вызовет a=(a)
на приемнике a
. Как указали другие , это может иметь значение, если вызов a=a
имеет побочные эффекты, такие как добавление ключей в хеш.
a ||= b
⇔ a = b unless a
??
Поведение этих утверждений отличается только тем, к чему они относятся, когда a
является правдивым. В этом случае a = b unless a
будет иметь значение nil
(хотя a
все равно не будет установлено, как ожидалось), тогда как a ||= b
будет иметь значение a
.
a ||= b
⇔ defined?(a) ? (a || a = b) : (a = b)
????
Все еще нет. Эти утверждения могут отличаться, если существует метод method_missing
, который возвращает истинное значение для a
. В этом случае a ||= b
будет вычислять все, что вернет method_missing
, и не будет пытаться установить a
, тогда как defined?(a) ? (a || a = b) : (a = b)
установит a
в b
и оценит в b
.
Хорошо, хорошо, так что эквивалентно a ||= b
? Есть ли способ выразить это в Ruby?
Ну, если предположить, что я ничего не пропускаю, я считаю, что a ||= b
функционально эквивалентен ... ( drumroll )
begin
a = nil if false
a || a = b
end
Держись! Разве это не первый пример с noop перед ним? Ну, не совсем. Помните, как я говорил ранее, a ||= b
не эквивалентен a || a = b
, когда a
является неопределенной локальной переменной? Ну, a = nil if false
гарантирует, что a
никогда не будет неопределенным, даже если эта строка никогда не выполняется. Локальные переменные в Ruby имеют лексическую область видимости.