Perl: Специальный массив @_ на самом деле не является псевдонимом?
Специальный массив @_
, где присутствуют все аргументы, переданные функции, на самом деле является псевдонимом переданных аргументов. Следовательно, любое изменение, которое мы делаем непосредственно на этот специальный массив @_
, также будет отражено в основном. Это ясно.
#!/usr/bin/perl
use warnings;
use strict;
$\="\n";
sub func {
print \@_;
$_++ for(@_);
}
my @arr=(2..4);
print \@arr;
func(@arr);
print "@arr";
В приведенной выше программе я ожидал, что ссылка @arr
и @_
будет указывать на одно и то же местоположение, поскольку это псевдоним. Но это не так.
При запуске выше:
ARRAY(0x1b644d0)
ARRAY(0x1b644e0)
3 4 5
Если они указывают на 2 разных местоположения, как изменения, выполненные в @_
, отражаются в @arr
?
Я вижу что-то не так? Пожалуйста, совет.
Ответы
Ответ 1
Это может ответить на ваш вопрос:
use warnings;
use strict;
$\="\n";
sub func {
print \@_;
$_++ for(@_);
print \$_ for @_;
}
my @arr=(2..4);
print \@arr;
func(@arr);
print "@arr";
print \$_ for @arr;
Выход
ARRAY(0x17fcba0)
ARRAY(0x1824288)
SCALAR(0x17fcc48)
SCALAR(0x18196f8)
SCALAR(0x1819710)
3 4 5
SCALAR(0x17fcc48)
SCALAR(0x18196f8)
SCALAR(0x1819710)
Как вы видите, отдельные аргументы имеют один и тот же адрес, но контейнер не совпадает. Если вы нажмете элемент на @_
в func
, @arr
не изменится (так что вы можете сделать shift
в funct
). Таким образом, каждый аргумент является псевдонимом, а элементы массива передаются как отдельные элементы. @_
содержит все элементы, переданные в подпрограмму. Если вы хотите изменить аргумент массива, вам необходимо передать его по ссылке.
Ответ 2
@_
не является псевдонимом; его элементы.
Помните, что
func(@arr);
совпадает с
func($arr[0], $arr[1], ...);
потому что единственное, что может быть передано в sub, это список скаляров, и массив вычисляет список его элементов в контексте списка.
Итак, это означает
func(@arr);
в основном совпадает с
local @_;
alias $_[0] = $arr[0];
alias $_[1] = $arr[1];
...
&func;
Изменение элементов @_
изменит элементы @arr
, но добавление и удаление элементов @_
не изменит @arr
, поскольку они представляют собой разные массивы.
>perl -E"@a=(4..6); sub { $_[0] = '!'; say @_; }->(@a); say @a;"
!56
!56
>perl -E"@a=(4..6); sub { splice(@_,0,1,'!'); say @_; }->(@a); say @a;"
!56
456