Приоритет оператора для And/&& в Ruby
У меня есть вопрос относительно ключевых слов и /&&/= в Ruby.
Документы ruby говорят, что приоритет для упомянутых ключевых слов: (1)&&, (2)=, (3) и.
У меня есть этот фрагмент кода, который я написал:
def f(n)
n
end
if a = f(2) and b = f(4) then
puts "1) #{a} #{b}"
end
if a = f(2) && b = f(4) then
puts "2) #{a} #{b}"
end
Выход:
1) 2 4 [Ожидается]
2) 4 4 [Почему?]
По какой-то причине использование && приводит к тому, что значения a и b равны 4?
5 ответов
Я не совсем понимаю вопрос, который вы задаете. Я имею в виду, что вы уже дали ответ, прежде чем даже задать вопрос: &&
крепче, чем =
в то время как and
связывает менее плотно, чем =
,
Итак, в первом случае выражение оценивается следующим образом:
( a=f(2) ) and ( b=f(4) )
( a= 2 ) and ( b=f(4) )
2 and ( b=f(4) ) # a=2
2 and ( b= 4 ) # a=2
2 and 4 # a=2; b=4
4 # a=2; b=4
Во втором случае оценка выглядит следующим образом:
a = ( f(2) && ( b=f(4) ) )
a = ( 2 && ( b=f(4) ) )
a = ( 2 && ( b= 4 ) )
a = ( 2 && 4 ) # b=4
a = 4 # b=4
4 # b=4; a=4
Причина проста: приоритет. Как вы говорите, заказ:
- &&
- знак равно
- а также
поскольку &&
имеет приоритет над =
, утверждение оценивается так:
if a = (f(2) && (b = f(4))) then
Что приводит к:
if a = (2 && 4) then
когда x
а также y
целые числа, x && y
возвращается y
, таким образом 2 && 4
результаты в a = 4
,
Для сравнения, первый оценивается так:
if (a = f(2)) and (b = f(4)) then
Единственная разница в двух формах - это приоритет (
and
связывает ниже, чем&&
).
Я не знаю конкретных правил, которые могут помочь в этой ситуации, но давайте использовать приоритеты операций. Используя правила приоритетов, мы можем разделить вычисление второго выражения на несколько шагов
1 f(2) && b => expr1
2 expr1 = f(4) => expr2
3 a = expr2
Очевидно, что на шаге 2 мы получаем неправильную ситуацию - слева от = стоит rvalue - временный объект, который нельзя присвоить никаким значением. Я предполагаю, что синтаксический анализатор нарушает правила приоритетной оценки выражений при возникновении таких ситуаций. Более подробно с расчетами выражений можно ознакомиться здесь
Если вы измените свой код, как это, вы получите то, что вы ожидаете
def f(n)
n
end
if (a = f(2) and b = f(4)) then
puts "1) #{a} #{b}"
end
if (a = f(2) and b = f(4)) then
puts "2) #{a} #{b}"
end
1) 2 4
2) 2 4