Я читаю книгу "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, и думал, что есть операторы списка слева и справа. Так что теперь, когда я понимаю, что это значит, я все понимаю.
Хорошо, для начала: операторы списков относятся к числу вещей с самым низким приоритетом в 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»
, оцениваемых в пустом контексте.
Все так, как вы говорите, за исключением части "это не имеет смысла".
Первое - это
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. Она определена и ничего не печатает.
Вот как эти утверждения будут выглядеть с полными скобками:
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". Это не то, что имеется в виду. Он пытается сказать, что все, что находится в правой части оператора списка, интерпретируется как аргументы этого оператора (если только вы не используете один из булевых операторов с очень низким приоритетом, таких как и
). Но то, что находится слева от оператора списка, не связано с этим оператором списка.