Список приоритетов операторов в Perl

Я читаю книгу "Beginning Perl", и она дает следующие два утверждения:

print "Test one: ", 6 > 3 && 3 > 4, "\n";
print "Test two: ", 6 > 3 and 3 > 4, "\n";

Первая строка ничего не печатает с новой строкой, вторая строка печатает 1 без новой строки

Я запутался в выводе. Согласно автору, второе утверждение дает странный вывод, потому что это все равно что сказать:

print ("Test two: ", 6 > 3) and 3 > 4, "\n";

Однако, почему первое утверждение не то же самое? Я думал, что это как-то связано с приоритетом печати. && имеет более высокий приоритет, чем print, поэтому сначала оценивается, а затем печатается. Принимая во внимание, что «и» имеет более низкий приоритет, чем print, поэтому 6> 3 будет напечатано, print возвращает 1, а затем это оценивается с помощью «и». Однако это не имеет смысла.

Я прочитал документацию Perl о том, как работает приоритет для операторов списков, но я до сих пор не понимаю этот пример. Не могли бы вы, ребята, проанализировать два утверждения и сказать, что напечатано первым? Можете ли вы также объяснить, что означает документация Perl, когда она упоминает операторы списков как «левые» и «правые»? Спасибо.


Большое спасибо всем за ваши ответы. Теперь я это понимаю. Я действительно делал то, что сказал cjm, и думал, что есть операторы списка слева и справа. Так что теперь, когда я понимаю, что это значит, я все понимаю.

8
задан Brian 3 November 2011 в 05:41
поделиться

3 ответа

Хорошо, для начала: операторы списков относятся к числу вещей с самым низким приоритетом в perl, но только справа . Вы спросите, что это значит: что ж, давайте упростим. Предположим, что существует листоп с именем foo . Неважно, что он делает, но он есть. Вы можете легко создать такую ​​вещь с помощью sub foo {map 10 * $ _, @_} , который возвращает каждый из своих аргументов, умноженных на десять. Это не мешает:

print 1, 2, 3; эквивалентно print (1, 2, 3);
print foo 1, 2, 3; эквивалентно to print (foo (1, 2, 3));
print 1, foo 2, 3; эквивалентно print (1, foo (2, 3));

Мы видим, что foo поглощает столько, сколько может с правой стороны - только конец оператора (пока ...) может остановить его. Если бы мы написали @array = (1, foo 2, 3); , это было бы эквивалентно @array = (1, foo (2, 3)); из-за, конечно, окончания круглые скобки остаются в силе.

Поскольку запятые также имеют очень низкий приоритет (чуть выше «Операторы списка (вправо)»), мы также можем поместить практически любое выражение, которое захотим, в аргументы листопа - это просто способ Perl убедиться, что в большинстве случаев нам не нужно добавлять круглые скобки. Математика, побитовые операторы, сравнения и даже совпадения регулярных выражений имеют более высокий приоритет.

Единственные вещи, которые делают имеют более низкий приоритет, - это прописанные логические связки и , или , xor и , а не . Итак, если мы напишем

foo 1, 2, 3 and 4;

, это означает (foo (1, 2, 3) и 4) - аргументы foo остановятся слева от и . В надуманном примере это кажется глупым, поэтому давайте превратим его в обычную идиому perl:

open $fh, '<', $filename or die "$! opening $filename";

, которая эквивалентна

(open($fh, '<', $filename) or die("$! opening $filename"));

, которая на самом деле в точности эквивалентна (и компилируется в)

die "$! opening $filename" unless open $fh, '<', $filename;

с использованием формы модификатора оператора , если только (который вообще не является оператором, разрешен только один раз для каждого оператора и идет только в конце оператора, поэтому он на самом деле вообще не имеет приоритета, но вы можете это рассмотреть как приоритет «ниже самого низкого» слева).

Так или иначе, возвращаясь к исходному образцу кода - аргументы print заканчиваются слева от и и справа от и - это совершенно отдельное выражение с запятой, которое вообще ничего не делает, потому что это всего лишь несколько констант 3> 4 и «\ n» , оцениваемых в пустом контексте.

12
ответ дан 5 December 2019 в 06:52
поделиться

Все так, как вы говорите, за исключением части "это не имеет смысла".

Первое - это

print "Test one: ", (6 > 3 && 3 > 4), "\n";

а второе

(print "Test two: ", 6 > 3) and (3 > 4, "\n");

Если включить предупреждения (use warnings), то вы получите предупреждение Useless use of a constant in void context, потому что правая часть and оценивается в список с элементами false и новой строкой, но никогда не используется.

edit: Исправлено мое утверждение 3>4 is undef. False не является undef. Она определена и ничего не печатает.

4
ответ дан 5 December 2019 в 06:52
поделиться

Вот как эти утверждения будут выглядеть с полными скобками:

print("Test one: ", ((6 > 3) && (3 > 4)), "\n");
print("Test two: ", (6 > 3)) and ((3 > 4), "\n");

> имеет наивысший приоритет, затем &&, затем ,, затем print, затем and.

6 > 3 оценивается как 1. 3 > 4 оценивается как false, что в Perl является специальным значением, которое равно 0 в числовом контексте, но пустой строке в строковом контексте (как здесь). Таким образом, ((6 > 3) && (3 > 4)) дает пустую строку.

Таким образом, первый оператор передает 3 аргумента для print: "Тест 1: ", пустая строка и новая строка. Он печатает каждый аргумент по порядку.

Второй оператор передает только 2 аргумента print: "Тест два: " и 1. Новая строка не печатается, потому что она не была передана в print.

Я не уверен, как объяснить "влево" и "вправо" лучше, чем в документации. Но, возможно, вас смущает то, что вы думаете, что есть "leftward list ops" и "rightward list ops". Это не то, что имеется в виду. Он пытается сказать, что все, что находится в правой части оператора списка, интерпретируется как аргументы этого оператора (если только вы не используете один из булевых операторов с очень низким приоритетом, таких как и). Но то, что находится слева от оператора списка, не связано с этим оператором списка.

8
ответ дан 5 December 2019 в 06:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: