Существует несколько способов создать подпрограмму, которая возвращает свои аргументы в виде массива:
sub array {[@_]} # returns an array reference that is a copy of its argument
sub array_verbose { # the same as array(), but spelled out
my @copy = @_;
return \@copy;
}
sub capture {\@_} # returns a reference to the actual argument array
Существует несколько важных различий между array
и capture
:
my ($x, $y) = (3, 4);
my $array = array $x, $y;
my $capture = capture $x, $y;
say "@$array, @$capture"; # prints '3 4, 3 4'
$x++;
say "@$array, @$capture"; # prints '3 4, 4 4'
$$capture[1] *= 2;
say "@$array, @$capture"; # prints '3 4, 4 8'
say "$x $y"; # prints '4 8'
Как показывают эти примеры, массив, созданный array()
, копируется по значению, и эти значения не зависят от исходных аргументов.Массив, созданный с помощью capture()
, сохраняет двунаправленный псевдоним для своего списка аргументов.
Другое отличие заключается в скорости.capture()
примерно на 40% быстрее, чем array()
, поскольку ему не нужно копировать элементы массива (или даже смотреть на них в этом отношении).Разница в скорости, конечно, будет варьироваться в зависимости от длины списка аргументов.
Дополнительный эффект capture()
, даже не затрагивающий его элементы, состоит в том, что если используется аргумент, который обычно выделяет память, это распределение будетне произойдет, пока не будет затронут аргумент:
my %hash;
my $hashcap = capture $hash{a}, $hash{b}, $hash{c};
say join ', ' => keys %hash; # prints nothing
$_++ for @$hashcap;
say join ', ' => keys %hash; # prints 'c, a, b'
В моем собственном коде я обычно пишу capture()
как cap()
или просто пишу его в строке:
my $y = sub{\@_}->(map $_**2, 1..10);