关于“<em>我可以grep
下一个元素吗”这个问题——让我们编写一个函数来为我们做这件事。
首先,我们遍历除最后一个以外的所有索引。当索引处的元素满足条件时,我们会记住下一个元素。我们可以这样写:
my @input = ...;
my @output = map { $input[$_ + 1] } # get the next element
grep { $input[$_] =~ /some condition/ } # grep all interesting indices
0 .. $#input - 1; # all indices but the last
或等效地:
my @input = ...;
my @output;
for my $i (0 .. $#input - 1) {
push @output, $input[$i + 1] if $input[$i] =~ /some condition/;
}
我们现在想把它抽象成一个函数。为此,我们将回调(或:匿名函数)作为第一个参数。然后我们将调用这个函数并$_
设置为当前元素。我们必须在设置它之前本地化该变量以避免污染该函数的任何调用者:
sub grepnext (&@) {
my $callback = shift;
# input is @_
my @out;
for my $i (0 .. $#_ - 1) {
# localize $_ and set it to the current element
local $_ = $_[$i];
push @out, $_[$i + 1] if $callback->();
}
return @out;
}
我们现在可以这样做:
my @after_red = grepnext { /red/ } qw(red cat blue dog);
我grepnext
以一种允许我们像上面那样调用它的方式声明。这使用了一个(&@)
原型。原型是一种功能,它允许我们在某些情况下更改函数调用的解析。它们非常强大,通常不应该使用。它们与命名参数无关,不能用于任何参数验证。此外,子例程必须在对其进行任何调用之前声明。
没有原型,我们必须使用这种形式:
my @after_red = grepnext sub{ /red/ }, qw(red cat blue dog);
无论哪种方式,@after_red
现在都将正确包含一个元素,即"cat"
.