Почему этот блок карты содержит явно бесполезный +?

Во время просмотра исходного кода я увидел следующие строки:

my @files_to_keep = qw (file1 file2);
my %keep = map { + $_ => 1 } @files_to_keep;

Что делает + в этом фрагменте кода? Я использовал Data::Dumper, чтобы увидеть, что вынимает знак "плюс", что-то делает, но результаты были одинаковыми:

  $ perl cleanme.pl
$VAR1 = {
          'file1' => 1,
          'file2' => 1
        };

Ответ 1

Это используется для предотвращения проблемы синтаксического анализа. Символ "плюс" заставляет интерпретатор вести себя как обычный блок, а не выражение.

Страх в том, что, возможно, вы пытаетесь создать hashreference, используя другую (выражение) формулировку map, как это.

@array_of_hashrefs = map {  "\L$_" => 1  }, @array

Обратите внимание на запятую. Тогда, если парсер догадывается, что вы делаете это, учитывая инструкцию в OP, будет синтаксическая ошибка для пропуски запятой! Чтобы увидеть разницу, попробуйте указать "$_". По какой-то причине анализатор воспринимает это как достаточно, чтобы вызвать поведение выражения.

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

Вот примеры из map документации.

%hash = map {  "\L$_" => 1  } @array  # perl guesses EXPR.  wrong
%hash = map { +"\L$_" => 1  } @array  # perl guesses BLOCK. right
%hash = map { ("\L$_" => 1) } @array  # this also works
%hash = map {  lc($_) => 1  } @array  # as does this.
%hash = map +( lc($_) => 1 ), @array  # this is EXPR and works!
%hash = map  ( lc($_), 1 ),   @array  # evaluates to (1, @array)

Для забавного чтения (стилистически) и случая, когда парсер ошибается, читайте это: http://blogs.perl.org/users/tom_wyant/2012/01/the-case-of-the-overloaded-curlys.html

Ответ 2

Оператор unary-plus просто возвращает свой операнд без изменений. Добавление одного из них даже не меняет контекста.

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


Например, map имеет два синтаксиса.

map EXPR, LIST

и

map BLOCK LIST

Блок начинается с {, но так же может быть выражение. Например, { } может быть блочным или хэш-конструктором.

Итак, как map сказать разницу? Догадывается. Это означает, что иногда это неправильно.

Один случай, когда догадывается неправильно, следующий:

map { $_ => 1 }, @list

Вы можете запрограммировать его правильно, используя + или ;.

map {; ...     # BLOCK
map +{ ...     # EXPR

Итак, в этом случае вы можете использовать

map +{ foo => $_ }, @list

Но я предпочитаю:

map({ foo => $_ }, @list)

Другим примером является то, что вы игнорируете parens вокруг аргументов, а первое выражение выражения начинается с символа.

print ($x+$y)*2;    # Same as: 2 * print($x+$y)

Его можно исправить с помощью

print +($x+$y)*2;

Но зачем наваливать на хак, чтобы избежать парнеров? Я предпочитаю

print(($x+$y)*2);