sub reduce(&@) {
my $expr = \&{shift @ARG};
my $result = shift @ARG;
while (scalar @ARG > 0) {
our $a = $result;
our $b = shift @ARG;
$result = $expr->();
}
return $result;
}
我无法理解这段代码中的一些语法。有人可以向我解释一下吗?例如\&
和$result = $expr->()
答案 0 :(得分:8)
\&name
返回对名为name
的子例程的引用。
$code_ref->()
调用$code_ref
引用的子例程。
$ perl -e'
sub f { CORE::say "Hi" }
my $code_ref = \&f;
$code_ref->();
'
Hi
在您的情况下,shift @ARG
返回子例程引用,所以
my $expr = \&{shift @ARG};
本来可以写成
my $expr = shift @ARG;
有点像做$y = $x+1-1;
。
请注意,reduce
的原型允许将其称为
reduce { ... } ...
但实际执行的是
reduce(sub { ... }, ...)
请注意,reduce
的此版本存在问题。您应该使用List::Util提供的那个。
local $a
和local $b
来避免破坏其调用者在$a
和$b
中可能拥有的值。reduce
期望其回调编译在与reduce
本身相同的包中。否则,回调子将无法使用$a
和$b
。our
声明变量实际上完全没用,因为$a
和$b
免于use strict;
检查,并且未声明使用{{1 }和$a
将访问完全相同的包变量。答案 1 :(得分:1)
查看一些List::Util::reduce()示例可能会有所帮助。
我们来看第一个:
$foo = reduce { $a > $b ? $a : $b } 1..10;
所以reduce
接受一个BLOCK
后跟一个LIST,函数签名声明:sub reduce(&@) {
。在我们的例子中,块是语句$a > $b ? $a : $b
,而列表是1..10
。来自文档:
通过在标量上下文中多次调用“BLOCK”来减少@list, 每次设置$ a和$ b。第一个电话将是$ a和$ b设置为 列表的前两个元素,后续调用将由 将$ a设置为上一次调用的结果,将$ b设置为下一个元素 在列表中。
返回上次调用“BLOCK”的结果。如果@list为空则 返回“undef”。如果@list只包含一个元素,那么该元素 返回并且不执行“BLOCK”。
现在到代码的注释版本:
$foo = reduce { $a > $b ? $a : $b } 1..10; # $foo will be set to 10
sub reduce(&@) {
# reduce() takes a BLOCK followed by a LIST
my $expr = \&{shift @ARG};
# $expr is now a subroutine reference, i.e.
# $expr = sub { $a > $b ? $a : $b };
# Start by setting $result to the first item in the list, 1
my $result = shift @ARG;
# While there are more items in the list...
while (scalar @ARG > 0) {
# Set $a to the current result
our $a = $result;
# Set $b to the next item in the list
our $b = shift @ARG;
# Set $result to the result of $a > $b ? $a : $b
$result = $expr->();
}
# List has now been reduced by the operation $a > $b ? $a : $b
return $result;
}