#perl
#perl
Вопрос:
Как бы мне написать функцию, которая возвращает свои аргументы в виде ссылки на массив?
Ответ №1:
sub f {
return [@_];
}
$ref = f(2, 3, 5);
print "@$refn";
[@foo]
Конструкция создает ссылку на новый анонимный массив (копию @foo
), в то время как @foo
конструкция создает ссылку на @foo
массив, содержимое которого позже может измениться.
Ответ №2:
Существует несколько способов создать подпрограмму, которая возвращает свои аргументы в виде массива:
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);