Iva*_*zar 18 perl arguments subroutine
我有一组子程序,如下所示:
sub foo_1($) {
my $name = shift;
my $f;
run_something();
open($f, $name) or die ("Couldn't open $name");
while (<$f>) {
//Something for foo_1()
}
close($f);
do_something_else();
}
Run Code Online (Sandbox Code Playgroud)
我有四个或更多看起来相同,唯一改变的是while块的主体.我想抽象一下并停止复制粘贴代码.
为了给出更多的上下文,不同的foo子程序是一个不同的有限状态机(FSM),它读取不同文件的内容并将数据提供给哈希引用.也许比我想要完成的事情更聪明.
Eri*_*rom 36
Perl提供了一个称为子例程原型的系统,允许您编写以类似于内置函数的方式解析的用户子.您要模拟的内置函数是map,grep或者sort每个都可以将块作为第一个参数.
要做到这一点与原型,可以使用sub name (&) {...}在&告诉Perl的第一个参数的函数或者是块(有或无sub),或文字子程序\&mysub.该(&)原型指定一个且只有一个说法,如果你需要的代码块后传递多个参数,因为你可以把它写(&@)这意味着,一个代码块后面的列表.
sub higher_order_fn (&@) {
my $code = \&{shift @_}; # ensure we have something like CODE
for (@_) {
$code->($_);
}
}
Run Code Online (Sandbox Code Playgroud)
该子例程将在传入列表的每个元素上运行传入的块.该\&{shift @_}看起来有点神秘,但它的作用是关闭名单的第一要素,这应该是一个代码块的变化.将&{...}值取消引用作为子例程(调用任何重载),然后\立即获取对它的引用.如果值是CODE引用,则返回不变.如果它是一个重载的对象,它将变成代码.如果无法强制转换为CODE,则会引发错误.
要调用此子例程,您可以编写:
higher_order_fn {$_ * 2} 1, 2, 3;
# or
higher_order_fn(sub {$_ * 2}, 1, 2, 3);
Run Code Online (Sandbox Code Playgroud)
(&@)允许您将参数写为map/ greplike块的原型仅在使用高阶函数作为函数时起作用.如果您将它用作方法,则应省略原型并以这种方式编写它:
sub higher_order_method {
my $self = shift;
my $code = \&{shift @_};
...
$code->() for @_;
}
...
$obj->higher_order_method(sub {...}, 'some', 'more', 'args', 'here');
Run Code Online (Sandbox Code Playgroud)
dax*_*xim 12
sub bar {
my ($coderef) = @_;
?
$coderef->($f, @arguments);
?
}
bar(sub { my ($f) = @_; while … }, @other_arguments);
Run Code Online (Sandbox Code Playgroud)
或者与命名的coderef纠缠不清:
my $while_sub = sub {
my ($f) = @_;
while …
?
};
bar($while_sub, @other_arguments);
Run Code Online (Sandbox Code Playgroud)
编辑:高阶Perl书充满了这种编程.
你想要&原型.
sub foo(&@) {
my ($callback) = shift;
...
$callback->(...);
...
}
Run Code Online (Sandbox Code Playgroud)
品牌
foo { ... } ...;
Run Code Online (Sandbox Code Playgroud)
相当于
foo(sub { ... }, ...);
Run Code Online (Sandbox Code Playgroud)