Приоритет оператора для 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 [ Почему?]

По какой-то причине использование && заставляет а и b оценивать до 4?

Ответ 1

Я не совсем понимаю вопрос, который вы задаете. Я имею в виду, что вы уже сами дали ответ, прежде чем задавать вопрос: && привязывается более жестко, чем =, а 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

Ответ 2

Причина проста: приоритет. Как вы говорите, порядок:

  • &&
  • =
  • и

Так как && имеет приоритет над =, оператор вычисляется следующим образом:

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 

Ответ 4

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

1 f(2) &&  b => expr1
2 expr1 = f(4) => expr2
3 a = expr2

Очевидно, что на шаге 2 мы получаем неверную ситуацию - в левой части = is rvalue - временный объект, который нельзя присвоить никаким значением. Я предполагаю, что синтаксический анализатор нарушает правила приоритетной оценки выражений при столкновении с такими ситуациями. Более подробную информацию о вычислениях выражений можно найти здесь

Ответ 5

если вы измените свой код таким образом, вы получите то, что ожидаете

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