Почему 'return a или b' является ошибкой выражения пустого значения в Ruby?

Это просто чудесно:

def foo
  a or b
end

Это тоже хорошо:

def foo
  return a || b
end

возвращает void value expression:

def foo
  return a or b
end

почему? Он даже не выполняется; он не выполняет проверку синтаксиса. Что делает void value expression В смысле?

3 ответов


return a or b трактуется как (return a) or b, и поэтому значение return a необходимо рассчитать значение (return a) or b, но поскольку return никогда не оставляет значение на месте (потому что он убегает из этой позиции), он не предназначен для возврата допустимого значения в исходной позиции. И поэтому все выражение остается с (some_void_value) or b, и застрял. Вот что это значит.


просто так or и низкий приоритет чем || что означает return a будет выполнено до or b, недоступен


С аналогичный вопрос я уже спрашивал, Стефан пояснил в комментарии, что or и and на самом деле операторы потока управления и не следует использовать как boolean операторы (|| и && соответственно).

он также ссылался на статья, которая объясняет причины этих операторов управления потоком:

and и or originate (как и многое из Ruby) в Perl. В Perl они в основном использовались для изменения потока управления, аналогичного if и unless заявление модификаторов. (...)

они приводят следующие примеры:

and

foo = 42 && foo / 2

это будет эквивалентно:

foo = (42 && foo) / 2 # => NoMethodError: undefined method `/' for nil:NilClass

цель состоит в том, чтобы присвоить номер к foo и переназначить его с половиной его стоимости. Таким образом and оператор полезен здесь из-за его низкого приоритета, он изменяет/управления что было бы нормальным поток отдельных выражений:

foo = 42 and foo / 2 # => 21

он также может быть использован в качестве обратного if заявление в цикле:

next if widget = widgets.pop

что эквивалентно:

widget = widgets.pop and next

or

полезно для сцепления выражений вместе!--37-->

если первое выражение не удается, выполните вторую, и так далее:

foo = get_foo() or raise "Could not find foo!"

его можно также использовать как:

отменено unless заявление модификатор:

raise "Not ready!" unless ready_to_rock?

что эквивалентно:

ready_to_rock? or raise "Not ready!"

, потому как Савва объяснил the a or b выражение в:

return a or b

ниже приоритет, чем return a который при выполнении выходит из текущего контекста и не предоставляет никакого значения (значение void). Затем это вызывает ошибку ( repl.это исполнение):

(repl):1: выражение значения void

puts return a or b
              ^~

этот ответ стал возможным из-за Стефан комментарии (спасибо).