我总是对perl中匿名subs的用途和用法感到有些困惑.我理解这个概念,但寻找这个实践的价值的例子和解释.
要明确:
sub foo { ... } # <--- named sub
sub { ... } # <--- anonymous sub
Run Code Online (Sandbox Code Playgroud)
例如:
$ perl -e 'print sub { 1 }'
CODE(0xa4ab6c)
Run Code Online (Sandbox Code Playgroud)
告诉我sub返回一个标量值.所以,我可以这样做:
$ perl -e '$a = sub { 1 }; print $a'
Run Code Online (Sandbox Code Playgroud)
对于与上面相同的输出.这当然适用于所有标量值,因此您可以使用匿名subs加载数组或散列.
问题是,我如何使用这些潜艇?我为什么要使用它们?
而对于一个金星来说,是否有任何问题只能用匿名子解决?
Eri*_*rom 11
匿名子程序可用于各种事物.
事件处理系统的回调:
my $obj = Some::Obj->new;
$obj->on_event(sub {...});
Run Code Online (Sandbox Code Playgroud)迭代器:
sub stream {my $args = \@_; sub {shift @$args}}
my $s = stream 1, 2, 3;
say $s->(); # 1
say $s->(); # 2
Run Code Online (Sandbox Code Playgroud)高阶函数:
sub apply (&@) {
my $code = shift;
$code->() for my @ret = @_;
@ret
}
my @clean = apply {s/\W+/_/g} 'some string', 'another string.';
say $clean[0]; # 'some_string'
Run Code Online (Sandbox Code Playgroud)创建别名数组:
my $alias = sub {\@_}->(my $x, my $y);
$alias[0]++;
$alias[1] = 5;
say "$x $y"; # '1 5''
Run Code Online (Sandbox Code Playgroud)使用闭包进行动态编程(例如创建一组仅相差很小的子程序):
for my $name (qw(list of names)) {
no strict 'refs';
*$name = sub {... something_with($name) ...};
}
Run Code Online (Sandbox Code Playgroud)没有匿名子例程可以执行命名子例程不能执行的任何操作的情况.该my $ref = sub {...}
构造等同于以下内容:
sub throw_away_name {...}
my $ref = \&throw_away_name;
Run Code Online (Sandbox Code Playgroud)
无需为每个子选择唯一的'throw_away_name'而烦恼.
等价也是另一种方式,sub name {...}
相当于:
BEGIN {*name = sub {...}}
Run Code Online (Sandbox Code Playgroud)
除了名称之外,任一方法创建的代码引用都是相同的.
要调用子例程引用,可以使用以下任何一个:
$code->(); # calls with no args
$code->(1, 2, 3); # calls with args (1, 2, 3)
&$code(); # calls with no args
&$code; # calls with whatever @_ currently is
Run Code Online (Sandbox Code Playgroud)
您甚至可以使用代码引用作为有福或无法使用的标量的方法:
my $list = sub {@{ $_[0] }};
say for [1 .. 10]->$list # which prints 1 .. 10
Run Code Online (Sandbox Code Playgroud)
您可以使用它来创建迭代器.
use strict;
use warnings;
use 5.012;
sub fib_it {
my ($m, $n) = (0, 0);
return sub {
my $val = ( $m + $n );
$val = 1 unless $val;
($m, $n) = ($n, $val);
return $val;
}
}
my $fibber = fib_it;
say $fibber->() for (1..3); ### 1 1 2
my $fibber2 = fib_it;
say $fibber2->() for (1..5); ### 1 1 2 3 5
say $fibber->() for (1..3); #### 3 5 8
Run Code Online (Sandbox Code Playgroud)
以下是您可能见过的类似内容:
@new_list = map { $_ + 1 } @old_list;
Run Code Online (Sandbox Code Playgroud)
并且:
@sorted = sort { $a <=> $b } @unsorted;
Run Code Online (Sandbox Code Playgroud)
这些都不是匿名潜艇,但他们的行为可以在你的函数中使用匿名潜艇模仿.它们不需要sub
关键字,因为函数(基本上)是原型,使它们的第一个参数成为子例程,而Perl认为这是一个特殊情况,sub
可以将其关闭.(函数还会在调用您提供的子例程之前将必需变量设置为有意义的值,以简化参数传递,但这与之无关.)
你可以编写自己喜欢map
的函数:
sub mapgrep (&@) { # make changes and also filter based on defined-ness
my ($func, @list) = @_;
my @new;
for my $i (@list) {
my $j = $func->($i);
push @new, $j if defined $j;
}
}
Run Code Online (Sandbox Code Playgroud)
让它与$ _一起工作的魔力在这里写得有点多 - 上面的版本仅适用于带参数的subs.
归档时间: |
|
查看次数: |
2817 次 |
最近记录: |