Странный смысл || и || = в Ruby (2.0, 1.9.3, jruby 1.7.4)
Рассмотрим следующий фрагмент irb из недавно запущенного сеанса:
irb:01> baz # => NameError, baz is not defined
irb:02> baz || baz = 0 # => NameError, baz is not defined
irb:03> baz # => nil
baz
была переменной undefined, и, пытаясь ее оценить, она произвела a NameError
. Однако каким-то образом после этой операции был определен baz
и имеет значение nil
. По-видимому, значение nil
было присвоено переменной baz
, хотя никто (явно) не просил ее об этом. Существует ли основной язык, почему это поведение желательно?
Каково правило, объясняющее это поведение и другие аналогично запутывающие конструкции, такие как:
irb:04> true if foo # => NameError
irb:05> foo # => NameError; name still undefined
irb:06> foo = (true if foo) # => nil
irb:07> foo # => nil; name defined as nil
irb:08> true || i = 0 || j = 2 # => i and j are nil; || appears nonlazy
irb:09> raise || quux = 1 # => RuntimeError, quux is nil
Ответы
Ответ 1
Я не знаю, желательно ли это, но это происходит из того, как Ruby анализирует код. Всякий раз, когда у вас есть кусок кода, который назначает локальную переменную, этой локальной переменной присваивается nil
, даже если этот фрагмент кода не оценивается. В вашей строке кода 2:
baz || baz = 0
первая baz
возвратила ошибку, потому что такая переменная не была назначена. Следовательно, присваивание baz = 0
, которое следует за ним, не оценивалось, но тем не менее оно было проанализировано, поэтому в контексте для этого была создана локальная переменная baz
и инициализируется на nil
.
С вашим вторым фрагментом кода foo
не назначается во время true if foo
и foo
. После этого foo = (true if foo)
имеет назначение foo
, поэтому, несмотря на то, что (true if foo)
оценивается до присвоения foo
, ошибка не возникает в этой строке.