Что делает '@ (' в этом Perl-коде? - PullRequest
9 голосов
/ 22 ноября 2011

В этом фрагменте кода:

    use strict;
    use warnings;
    use Data::Dumper;
    my $r = [qw(testing this thing)];

    print Dumper($r);
    foreach my $row (@({$r})
    {
        print "$row\n";
        $row .= 'mod';
    }
    print Dumper($r);
    print Dumper(@({$r});

Я понял, что '(' после '@' в foreach вызывает неправильную петлю. Я понятия не имею, почему этот код даже работает, так как нет конечных скобок. Что это делает? Похоже, он создает новую переменную на лету, но не должен был запускаться use strict или что-то в этом роде?

Пожалуйста, помогите объяснить, что делает "@(" и почему он по-прежнему работает без конечных скобок.

Ответы [ 4 ]

8 голосов
/ 22 ноября 2011

Это фрагмент хеша переменной %(, который является частью глобуса *( и освобождается от строгих переменных.Это верно для переменных, которые Perl предопределил, в данном случае $(, а также для всех других слотов глобуса для имен знаков препинания.Все переменные пунктуации являются глобальными для всех пакетов, и их полностью квалифицированные имена являются краткими формами: $), @), %), &) ... Поскольку strict 'vars' не применяется к полностью квалифицированным именам, нетиз этих имен ошибки.

Расширение немного:

@({$r};
@{(}{$r};
@{'main::('}{$r};  # needs strict refs to be off

Все эти строки эквивалентны.

С помощью use warnings; perl сообщит вам, что было бы лучше написать фрагмент одного значения с символом $:

$({$r};
${(}{$r};
${'main::('}{$r};  # needs strict refs to be off

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

Для получения более подробной информации на справочной странице perlvar показаны все переменные пунктуации с хотя бы одним символом или другим.И если вам нужна ссылка на область видимости переменных пунктуации, то в package docs есть это.


Все переменные пунктуации также защищены от used only once предупреждений, и это можетбыть ошибкой ...

3 голосов
/ 22 ноября 2011

@({$r} - это фрагмент хеша (задокументированный в perldata ) хеша %(.

%h = (a=>1, b=>2, c=>3);
say for @h{qw( a c )};  # 1 3

Сам Perl не использует %(, поэтому он былбезусловно, пустой.

Вы наверняка хотели использовать @{$r}, довольно сложный способ или писать @$r.

2 голосов
/ 22 ноября 2011

Когда я запускаю perl -cw на нем, он говорит:

Scalar value @({$r} better written as $({$r} at tmp.pl line 7.
Scalar value @({$r} better written as $({$r} at tmp.pl line 13.

$r является ссылкой на массив. Как только что написал Эрик Стром, @({$r} - это фрагмент хеш-переменной %(.

Вы никогда не объявляли %(, и это не одна из предопределенных переменных, перечисленных в perldoc perlvar. Так почему же use strict; use warnings; не заставляет Perl жаловаться на это? Вероятно, это просто предполагает, что любая переменная, имя которой является символом пунктуации, предопределена (проще, чем отслеживать, какие из них действительно есть, некоторые из которых могут быть undef в любом случае).

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

Похоже, это просто опечатка, на которую по непонятным причинам Perl не пожаловался.

Измените @({$r} на @{$r}, чтобы сделать то, что вы (предположительно) действительно хотели сделать.

0 голосов
/ 22 ноября 2011

Мне не показалось, что это хеш-фрагмент, пока я не проверил его через B :: Concise

$ perl -MO=Concise junk 
    Scalar value @({$r} better written as $({$r} at junk line 7.
    Scalar value @({$r} better written as $({$r} at junk line 13.
    junk syntax OK
    1l <@> leave[1 ref] vKP/REFC ->(end)
    1     <0> enter ->2
    ...
    ...
    1h             <@> hslice lKM ->1i
    1d                <0> pushmark s ->1e
    1e                <0> padsv[$r:335,339] l ->1f
    1g                <1> rv2hv[t17] sKR/3 ->1h
    1f                   <#> gv[*(] s ->1g
    -              <1> ex-rv2cv sK/2 ->-
    1i                <#> gv[*Dumper] s ->1j

hslice означает хеш-фрагмент :) узнайте свой B:: дерево, это действительно полезно

...