2012-02-06 2 views
10

Я пытаюсь вычислить выражение (a=10) || (rr=20) а переменная р-р не определенИмеет ли || оператор оценивает второй аргумент, даже если первый аргумент верен?

так набрав rr в консоли рубиновой перед вычислением предыдущего выражения возвращают

rr 
NameError: undefined local variable or method `rr' for main:Object 
from (irb):1 
from :0 

Когда я пишу выражение (a=10) || (rr=20) возвращает 10, и когда я пишу Р.Р. потом он говорит nil

(a=10) || (rr=20) 
rr # => nil 

так, почему это происходит? Не следует определять rr только в том случае, если второй аргумент || оператор оценивается, который никогда не должен основываться на документации?

+1

Существует различие между условными операциями с коротким замыканием (не оценивая второе условие, если первое ложно) и не объявляет переменную. Ваша проблема связана со второй проблемой. – DOK

+1

Зная, когда локальная переменная находится в вашей области, сложна в Ruby. Попробуйте запустить 'a + 1, если a = 5'. Вы можете ожидать, что он установит значение 5, а затем вернет 6, но на самом деле он установит 'a' и THEN жалуется на неопределенность' a'. –

ответ

10

Это происходит потому, что интерпретатор ruby ​​определяет переменную, когда видит ее присвоение (но до того, как она выполнит фактическую строку кода). Вы можете узнать больше об этом in this answer.

логическое ИЛИ (||) выражение будет оценивать на значение выражения левой руки, если это не nil, а не false, иначе || будет оценивать на значение правого выражения руки.

В вашем примере интерпретатор рубин видит назначение в a и rr (но не выполняет эту линию еще), и инициализирует (определяет, создает) a и rr с nil. Затем он выполняет выражение ||. В этом выражении ||a присваивается 10 и возвращается 10. r=20 не оценивается, и rr не изменен (он по-прежнему nil). Вот почему в следующей строке rr есть nil.

+0

Переменная * не * инициализирована, она просто определена. Поэтому он оценивает значение «nil»: поскольку неинициализированные переменные оцениваются в «nil» в Ruby. Если он * был * инициализирован, он будет оценивать значение '20', а не' nil'. –

+0

@ JörgWMittag, tnx для правильной формулировки. * initialized * в моем ответе действительно должен быть * определен * –

3

Я думаю, что определение переменных происходит на этапе синтаксического анализа, а не в момент выполнения. Поэтому, когда он оценивает линию, она анализирует все это, и переменная определена, но не назначена.

+0

* Точно *. Это правильный ответ. Переменная * определена *, поскольку переменные определены, когда в коде есть назначение. Но это * не * инициализировано или назначено, потому что присваивание никогда не выполняется. Следовательно, он вычисляет значение «nil», потому что это неинициализированные переменные оцениваются в Ruby. –

2

Когда парсер обнаруживает переменную, он автоматически действует в контексте, в котором он определен. Оценка rr сама по себе недействительна. Оценка rr=20 достаточно, чтобы вызвать определение, даже если присвоение значения никогда не происходит.

Это причуда того, как Рубин пытается различить переменные и вызовы методов. Он несовершенен, но обычно работает лучше.

4

Как указано в @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), р-р = 20 не будет выполняться, так как выражение рубинового a=10 возвращает true. Обратите внимание, что в выражении присваивания ruby ​​возвращает true, кроме nil and false.