Подтвердить что ты не робот

Perl vivification вопрос при разыменовании undefined ссылка на массив

Мне сложно понять, почему следующие работы:

my $array_reference;
foreach $element (@{$array_reference}) {
# some code
}

в то время как следующее не работает

my $array_reference;
if (scalar (@{$array_reference}) {
    # some code here
}

Я понимаю, что perl приносит в жизнь (автоматически оживляет) ссылку undefined. Но я все еще запутался, как в том, почему последний сегмент кода вызывает FATAL.

4b9b3361

Ответ 1

Выделение autovivify в контексте lvalue (значение, когда ожидается модифицируемое значение), и foreach создает контекст lvalue.

>perl -E"$$x = 1;  say $x;"
SCALAR(0x74b024)

>perl -E"++$$x;  say $x;"
SCALAR(0x2eb024)

>perl -E"\$$x;  say $x;"
SCALAR(0x30b024)

>perl -E"sub {}->($$x);  say $x;"
SCALAR(0x27b03c)

>perl -E"for ($$x) {}  say $x;"
SCALAR(0x25b03c)

Последние два создают контекст lvalue, потому что им нужно значение, к которому относятся псевдоним $_[0] и $_ (соответственно).

Ответ 2

Perl имеет несоответствия в этой области, но в целом код, который может модифицировать структуру, автогенерирует, а код, который этого не сделает, не будет. И если он не автовивит, он пытается разыменовать значение undefined, которое вызывает предупреждение или в use strict "refs" исключение.

Ответ 3

Я думаю, глядя на perlref, что это ожидаемое поведение:

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

Аналогичная вещь для foreach происходит с push() и друзьями:

my $f;
push @$f, 1;
say @$f;

Хотя не с новыми версиями can-just-take-a-reference:

my $f = [];
push $f, 1;
say @$f;

работает, а

my $f;
push $f, 1;
say @$f;

нет, что, по моему мнению, разумно, поскольку толчок не знает, что вы на самом деле имели в виду.

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