= и операторы в Perl - PullRequest
       3

= и операторы в Perl

4 голосов
/ 18 февраля 2011

Пожалуйста, объясните это внешне противоречивое поведение:

$a = b, c;
print $a; # this prints: b

$a = (b, c);
print $a; # this prints: c

Ответы [ 4 ]

16 голосов
/ 18 февраля 2011

Оператор = имеет более высокий приоритет, чем ,. А оператор запятой отбрасывает свой левый аргумент и возвращает правый.

Обратите внимание, что оператор запятой ведет себя по-разному в зависимости от контекста. От perldoc perlop :

Двоичный "," является оператором запятой. В скалярный контекст он оценивает свой левый аргумент, выбрасывает это значение, то оценивает свой правильный аргумент и возвращает это значение. Это так же, как Оператор запятой C.

В контексте списка это просто список разделитель аргументов, и вставляет оба его аргументы в список. Эти аргументы также оцениваются слева направо.

8 голосов
/ 18 февраля 2011

Поскольку ответ Юджина оставляет некоторые вопросы от ОП, я пытаюсь объяснить на основании этого:

$a = "b", "c";
print $a;

Здесь левый аргумент равен $a = "b", поскольку = имеет более высокий приоритет, чем ,это будет оценено в первую очередь.После этого $a содержит "b".

Правильный аргумент - "c" и будет возвращен, как я скоро покажу.

В тот момент, когда вы печатаете $a, это очевиднопечать b на вашем экране.

$a = ("b", "c");
print $a;

Здесь термин ("b","c") будет оцениваться первым из-за более высокого приоритета скобок.Он возвращает "c", и это будет присвоено $a.

Так что здесь вы печатаете "c".

$var = ($a = "b","c");
print $var;
print $a;

Здесь $a содержит "b" и $varсодержит «c».

Как только вы получите правила приоритета, это будет совершенно непротиворечиво

3 голосов
/ 20 февраля 2011

Существует простой способ увидеть, как Perl обрабатывает оба примера, просто запустите их с помощью:

perl -M<a href="http://http://perldoc.perl.org/O.html" rel="nofollow">O</a>=<a href="http://perldoc.perl.org/B/Deparse.html" rel="nofollow">Deparse</a>,<a href="http://perldoc.perl.org/B/Deparse.html#%2A-p%2A" rel="nofollow">-p</a> -e'...'

Как видите, разница в том, что порядок операций немного отличается от того, о котором вы могли подозревать.

perl -MO=Deparse,-p -e'$a = a, b;print $a'
(($a = 'a'), '???');
print($a);
perl -MO=Deparse,-p -e'$a = (a, b);print $a'
($a = ('???', 'b'));
print($a);

Примечание: вы видите '???', потому что исходное значение было оптимизировано.

3 голосов
/ 19 февраля 2011

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

Первая концепция заключается в том, что означают сигилы $ и @ (здесь мы не будем обсуждать %).@ означает несколько предметов (сказано "эти вещи").$ означает один предмет (сказал "эта вещь").Чтобы получить первый элемент массива @a, вы можете сделать $first = $a[0], получить последний элемент: $last = $a[-1].NB не @a[0] или @a[-1].Вы можете нарезать, выполнив @shorter = @longer[1,2].

Вторая концепция - это различие между пустым, скалярным и списочным контекстом.В Perl есть концепция контекста, в котором используются ваши контейнеры (скаляры, массивы и т. Д.).Простой способ убедиться в том, что если вы сохраняете список (мы перейдем к нему) как массив @array = ("cow", "sheep", "llama"), тогда мы сохраняем массив как скаляр $size = @array, мы получаем длину массива.Мы также можем форсировать это поведение, используя оператор scalar, такой как print scalar @array.Я скажу это еще раз для ясности: массив (не список) в скалярном контексте будет возвращать не элемент (как список), а скорее длину массива.

Помните, что перед вамииспользуйте символ $, если вы ожидаете только один предмет, то есть $first = $a[0].Таким образом, вы знаете, что находитесь в скалярном контексте.Теперь, когда вы вызываете $length = @array, вы можете ясно видеть, что вы вызываете массив в скалярном контексте, и, таким образом, вы запускаете специальное свойство массива в контексте списка, вы получаете его длину.

Это имеет другой хорошийфункция для тестирования, если есть элемент в массиве.print '@array contains items' if @array; print '@array is empty' unless @array.Тесты if /лачков заставляют скалярный контекст для массива, поэтому if видит длину массива, а не его элементы.Поскольку все числовые значения являются «истинными», кроме нуля, если массив имеет ненулевую длину, оператор, если @array оценивается как истинный, и вы получаете оператор печати. ​​

Пустой контекст означает, что возвращаемое значениенекоторые операции игнорируются.Полезной операцией в пустом контексте может быть что-то вроде увеличения.$n = 1; $n++; print $n; В этом примере $n++ (приращение после возврата) находилось в пустом контексте, поскольку его возвращаемое значение «1» не использовалось (сохранено, напечатано и т. Д.).

Третья концепция - это разница междусписок и массив.Список - это упорядоченный набор значений, а массив - это контейнер, который содержит упорядоченный набор значений.Вы можете увидеть разницу, например, в гимнастике, которую нужно сделать, чтобы получить определенный элемент после использования sort без предварительного сохранения результата (например, попробуйте pop sort { $a cmp $b } @array, который не работает, потому что pop не действует только на список, толькомассив).

Теперь мы можем спросить, когда вы попробуете свои примеры, что бы вы хотели, чтобы Perl делал в этих случаях?Как уже говорили другие, это зависит от приоритета.

В вашем первом примере, поскольку оператор = имеет более высокий приоритет, чем ,, вы фактически не присваивали список переменной, вы сделали что-то более похожее на ($a = "b"), ("c"), что эффективноничего со строкой "с".На самом деле это было названо в пустом контексте.С включенными предупреждениями, поскольку эта операция ничего не выполняет, Perl пытается предупредить вас, что вы, вероятно, не хотели делать это с сообщением: Useless use of a constant in void context.

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

my @animals = ("cow", "sheep", "llama");
my $return;
foreach my $animal (@animals) {
  $return = $animal;
}
print $return;

И, следовательно, вы получаете последний элемент списка (каноническое отличие состоит в том, что предыдущие значения никогда не сохранялись тогдаперезаписан, однако логика аналогична).

Есть способы сохранить что-то, что выглядит как список в скаляре, но это включает ссылки.Подробнее об этом читайте в perldoc perlreftut.

Надеюсь, это немного прояснит ситуацию.В заключение я скажу, что пока вы не овладеете правилами приоритета Perl, никогда не помешает поставить явные скобки для списков и аргументов функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...