Приоритет оператора списка в Perl - PullRequest
8 голосов
/ 09 августа 2010

Я читаю книгу «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, и думал, что есть левый и правый операторы списка.Итак, теперь, когда я понимаю, что это значит, я понимаю все это.

Ответы [ 3 ]

12 голосов
/ 09 августа 2010

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

print 1, 2, 3; эквивалентно print( 1, 2, 3 );
print foo 1, 2, 3; эквивалентно 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 убедиться, что нам не нужно добавлять скобки большую часть времени. Математические, побитовые операторы, сравнения, даже совпадения с регулярными выражениями имеют более высокий приоритет.

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

foo 1, 2, 3 and 4;

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

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

, что эквивалентно

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

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

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

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

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

8 голосов
/ 09 августа 2010

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

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: "Test one: ", пустой строке и символу новой строки.Он печатает каждый аргумент по порядку.

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

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

4 голосов
/ 09 августа 2010

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

Первый

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 недействительные претензии. Ложь не является неопределенной. Он определен и ничего не печатает.

...