Perl 提供了一个称为子程序原型的系统,它允许您编写用户子程序,这些子程序以类似于内置函数的方式进行解析。您要模拟的内置函数是map
、grep
或sort
,每个都可以将块作为其第一个参数。
要使用原型做到这一点,您可以使用sub name (&) {...}
where&
告诉 perl 函数的第一个参数是一个块(有或没有sub
),或者是一个文字子例程\&mysub
。原型指定了(&)
一个且只有一个参数,如果你需要在代码块之后传递多个参数,你可以写成(&@)
这意味着,一个代码块后跟一个列表。
sub higher_order_fn (&@) {
my $code = \&{shift @_}; # ensure we have something like CODE
for (@_) {
$code->($_);
}
}
该子例程将在传入列表的每个元素上运行传入块。\&{shift @_}
看起来有点神秘,但它所做的是将列表的第一个元素移开,这应该是一个代码块。取消引用该&{...}
值作为子例程(调用任何重载),然后\
立即获取对它的引用。如果该值是一个 CODE ref,那么它会原封不动地返回。如果它是重载对象,则将其转换为代码。如果无法强制转换为 CODE,则会引发错误。
要调用此子例程,您将编写:
higher_order_fn {$_ * 2} 1, 2, 3;
# or
higher_order_fn(sub {$_ * 2}, 1, 2, 3);
(&@)
允许您将参数编写为map
/ like 块的原型grep
仅在将高阶函数用作函数时才有效。如果您将其用作方法,则应省略原型并这样编写:
sub higher_order_method {
my $self = shift;
my $code = \&{shift @_};
...
$code->() for @_;
}
...
$obj->higher_order_method(sub {...}, 'some', 'more', 'args', 'here');