Хотя принятый ответ реализует map
-подобную функцию, он НЕ делает это так, как это делает perl.Важной частью for
, foreach
, map
и grep
является то, что $_
, который они вам предоставляют, всегда является псевдонимом значений в списке аргументов.Это означает, что вызов чего-то вроде s/a/b/
в любой из этих конструкций изменит элементы, с которыми они были вызваны.Это позволяет вам писать что-то вроде:
my ($x, $y) = qw(foo bar);
$_ .= '!' for $x, $y;
say "$x $y"; # foo! bar!
map {s/$/!!!/} $x, $y;
say "$x $y"; # foo!!!! bar!!!!
Поскольку в вашем вопросе вы попросили Map
использовать ссылки на массивы, а не на массивы, вот версия, которая работает с ссылками на массивы и которая настолько близкак встроенному map
, как вы можете получить в чистом Perl.
use 5.010;
use warnings;
use strict;
sub Map (&\@) {
my ($code, $array) = splice @_;
my @return;
push @return, &$code for @$array;
@return
}
my @sample = qw(1 2 3 4 5);
say join ', ' => Map { $_ * $_ } @sample; # 1, 4, 9, 16, 25
say join ', ' => map { $_ * $_ } @sample; # 1, 4, 9, 16, 25
В Map
прототип (&\@)
сообщает Perl, что голое слово Map
будет проанализировано с правилами, отличными от обычныхподпрограмма.&
указывает, что первый аргумент будет либо пустым блоком Map {...} NEXT
, либо ссылкой на буквальный код Map \&somesub, NEXT
.Обратите внимание на запятую между аргументами в последней версии.Прототип \@
указывает, что следующий аргумент начнется с @
и будет передан как ссылка на массив.
Наконец, строка splice @_
очищает @_
, а не просто копирует значения из,Это так, что строка &$code
будет видеть пустую @_
, а не полученные аргументы Map
.Причина &$code
заключается в том, что это самый быстрый способ вызова подпрограммы, и он настолько близок к стилю вызова multicall, который использует map
, насколько вы можете получить без использования C. Этот стиль вызова идеально подходит для этого использования,поскольку аргумент блока находится в $_
, что не требует каких-либо манипуляций со стеком.
В приведенном выше коде я немного изменяю и позволяю for
выполнить работу по локализации $_
.Это хорошо для производительности, но чтобы увидеть, как это работает, вот эта строка переписана:
for my $i (0 .. $#$array) { # for each index
local *_ = \$$array[$i]; # install alias into $_
push @return, &$code;
}