Предшествует ли присваивание логическому оператору в Ruby? - PullRequest
2 голосов
/ 03 августа 2020

Я столкнулся со странной ситуацией в состоянии if Ruby. Вот пример кода для воспроизведения ситуации.

p1 = /hello/
p2 = /world/

s = "hello, world"

if m1 = s.match(p1) && m2 = s.match(p2)
    puts "m1=#{m1}"
    puts "m2=#{m2}"
end

Результатом будет

m1=world
m2=world

Но я ожидал m1=hello, потому что оператор && имеет более высокий приоритет в Ruby операторах.

Этот код

if m1 = s.match(p1) && m2 = s.match(p2)

, кажется, интерпретируется как

if m1 = (s.match(p1) && m2 = s.match(p2))

Почему предшествует логический оператор И && над оператором присваивания =?

Ответы [ 3 ]

4 голосов
/ 03 августа 2020

В ruby почти все (см. Комментарии) возвращает значение.

Оператор && возвращает последнее выражение справа. Таким образом, 1 && 3 дает 3. && коротит замыкание на первом ложном значении. Он возвращает либо это значение, либо последнее вычисленное правдивое выражение.

|| возвращает первое выражение слева от него - поэтому 1 || 3 дает 1. || приведет к короткому замыканию на первом истинном значении, возвращая его.

Проверьте это различие:

1 + 5 * 3 + 1
# => 17 

1 + 5 && 3 + 1
# => 4

1 + 5 || 3 + 1
# => 6 

Это порядок оценки в m1 = s.match(p1) && m2 = s.match(p2)

  1. s.match(p1) => «привет»
  2. && => оценить все справа
  3. m2 = s.match(p2) => «мир»
  4. m1 = "hello" && "world" => «мир»

Ваше присвоение m2 возвращает значение, которое используется для второй части выражение &&, «мир». Присваивания в ruby также возвращают значение!

Таким образом, у вас будут m1 и m2 со значением «world».

0 голосов
/ 03 августа 2020

Используя только правила приоритета, ваш код будет читать:

if m1 = (s.match(p1) && m2) = s.match(p2)

Поскольку = имеет ассоциативность справа налево, вы получите синтаксическую ошибку при попытке сделать:

(s.match(p1) && m2) = s.match(p2)
0 голосов
/ 03 августа 2020

m1 = s.match(p1) && m2 = s.match(p2)

&& имеет более высокий приоритет, чем =, поэтому сначала выполняется операция &&, которая ниже

s.match(p1) && m2 = s.match(p2)
=> 'hello' && m2 = 'world'
=> 'world'

, world присваивается m2 возвращает m2, что равно world, а затем выполняет следующую операцию присваивания.

m1 = {OUTPUT OF (s.match(p1) && m2 = s.match(p2))}

m1 = 'world'

Прочитайте о Приоритет логических операторов в Ruby

Лучше использовать скобки, чтобы сделать его более явным

if (m1 = s.match(p1)) && (m2 = s.match(p2))
  ...
end

ИЛИ можно сначала выполнить операцию присваивания

m1 = s.match(p1)
m2 = s.match(p2)
if m1 && m2
  ...
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...