Имеет ли || оператор оценивает второй аргумент, даже если первый аргумент верен?
Я пытаюсь оценить выражение (a=10) || (rr=20)
, в то время как переменная rr не определена
набрав rr
в консоли ruby, прежде чем оценивать предыдущее выражение, верните
rr
NameError: undefined local variable or method `rr' for main:Object
from (irb):1
from :0
Когда я пишу выражение (a=10) || (rr=20)
, он возвращает 10, а когда я пишу rr после этого, он говорит nil
(a=10) || (rr=20)
rr # => nil
Итак, почему это происходит? Не следует определять rr только в том случае, если второй аргумент || вычисляется оператор, который никогда не должен основываться на документации?
Ответы
Ответ 1
Это происходит потому, что интерпретатор ruby определяет переменную, когда видит ее присвоение (но до того, как она выполнит фактическую строку кода). Вы можете прочитать об этом в этом ответе.
Булево выражение OR (||
) будет оценивать значение выражения левой руки, если оно не nil
, а не false
, else ||
будет оценивать значение выражения правой руки.
В вашем примере интерпретатор ruby видит назначение a
и rr
(но еще не выполняет эту строку) и инициализирует (определяет, создает) a
и rr
с помощью nil
, Затем он выполняет выражение ||
. В этом выражении ||
a
присваивается 10
и возвращается 10
. r=20
не оценивается, а rr
не изменяется (он все еще nil
). Вот почему в следующей строке rr
есть nil
.
Ответ 2
Как указано в @DOC, &&
и ||
известны как условные операторы short circuited
.
In case of ||, if the left part of || expression returns true, the right part won't be executed.
Это означает, что правая часть будет выполнена только в том случае, если левая часть выражения ||
возвращает false.
In case of &&, right part of the
&& expression will be executed only if left part of && returns true.
В данном сценарии (a=10) || (rr=20)
, rr = 20 не будет выполняться, так как выражение ruby a=10
возвращает true
. Обратите внимание, что в выражении присваивания ruby возвращает true, кроме nil and false
.
Ответ 3
Я думаю, что определение переменных происходит на этапе синтаксического анализа, а не в момент выполнения. Поэтому, когда он оценивает линию, он анализирует все это, и переменная определена, но не назначена.
Ответ 4
Когда парсер обнаруживает переменную, он автоматически действует в контексте, в котором он определен. Оценка rr
сама по себе недействительна. Оценка rr=20
достаточна, чтобы вызвать определение, даже если присвоение значения никогда не происходит.
Это причуда того, как Ruby пытается различать переменные и вызовы методов. Он несовершенен, но обычно работает наилучшим образом.