我如何编写一个接受像map函数那样的函数?
示例:
$func = sub { print $_[0], "hi\n" };
&something($f);
sub something
{
my $func = shift;
for ($i = 0; $i < 5; $i++)
{ $func->($i); }
}
工作正常。
但是如果我做了
&something( { print $_[0], "hi\n" } );
它不会工作,并说func是一个未定义的引用。
所以我的问题是如何编写一个接受perls map function等参数的函数?
map { s/a/b/g } @somelist;
答案 0 :(得分:17)
map
函数具有非常神奇的语法,除非你有充分的理由,否则你可能不想复制它。只需使用常规的匿名子,如下所示:
something(sub { print $_[0], "hi\n" });
但是,如果你真的想这样做,你需要使用prototype:
sub my_map (&@) {
my ($func, @values) = @_;
my @ret;
for (@values) {
push @ret, $func->($_);
}
return @ret;
}
my @values = my_map { $_ + 1 } qw(1 2 3 4);
print "@values"; # 2 3 4 5
(注意$_
是动态范围的,因此它在调用者中的任何值都保留在函数中。)
List::Util
和List::MoreUtils
做了很多事情来创建看起来内置并且像map
/ grep
的变体一样的函数。这是唯一一个应该使用这种东西的情况。
答案 1 :(得分:6)
首先,在调用&
时不要使用sub
。来自perldoc perlsub
:
子程序可以递归调用。如果使用
&
形式调用子例程,则参数列表是可选的,如果省略,则不为子例程设置@_
数组:@_
数组。调用对子程序可见。这是新用户可能希望避免的效率机制。
如果您希望能够将普通块传递给“sub something
”,则需要使用原型,如下所示:
sub something(&@);
# later
sub something(&@) {
my ($coderef, @args) = @_;
}
我个人只会传递一个明确的subref:
something( sub { } );
答案 2 :(得分:1)
&something( { print $_[0], "hi\n" } );
# ^^^ this isn't a reference
&something( sub { print $_[0], "hi\n" } ); # works just fine