Согласно §11.3.1.2.2 проекта спецификации ISO ,
CACHE[:some_key] ||= "Some String"
расширяется до
o = CACHE
*l = :some_key
v = o.[](*l)
w = "Some String"
x = v || w
l << x
o.[]=(*l)
x
Или, в более общем случае
primary_expression[indexing_argument_list] ω= expression
(я использую ω
здесь для обозначения любого оператора, так что это может быть ||=
, +=
, *=
, >>=
, %=
, & hellip;)
Расширяется до:
o = primary_expression
*l = indexing_argument_list
v = o.[](*l)
w = expression
x = v ω w
l << x
o.[]=(*l)
x
Итак, согласно спецификации, []=
будет всегда вызываться. Но на самом деле это не так в текущих реализациях (я тестировал MRI, YARV, Rubinius, JRuby и IronRuby):
def (h = {}).[]=(k, v) p "Setting #{k} to #{v}"; super end
h[:key] ||= :value # => :value
# "Setting key to value"
h[:key] ||= :value # => :value
Итак, очевидно, что либо спецификация неверна, либо все пять выпущенных в настоящее время реализаций неверны. А поскольку целью спецификации является описание поведения существующих реализаций, очевидно, что спецификация должна быть неправильной.
В общем, в первом приближении
a ||= b
расширяется до
a || a = b
Тем не менее, здесь задействованы все виды субподрядчиков, например, является ли a
неопределенным, является ли a
простой переменной или более сложным выражением типа foo[bar]
или foo.bar
и т. Д.
См. Также некоторые другие примеры того же вопроса, которые уже были заданы и даны ответы здесь, в StackOverflow (например, этот ). Кроме того, этот вопрос обсуждался так много раз в списке рассылки ruby-talk, что теперь есть обсуждений , единственной целью которых является обобщение других обсуждений. (Хотя, пожалуйста, обратите внимание, что этот список далеко не полный.)