我对perl中的代码块有疑问.给出以下代码:
my @newArr = sort { $a <=> $b } @oldArr;
Run Code Online (Sandbox Code Playgroud)
使用代码块作为参数.
我可以把它重写为:
sub sortFunc {
return $a <=> $b;
}
my @newArr = sort sortFunc @oldArr;
Run Code Online (Sandbox Code Playgroud)
我试图弄清楚这种机制是如何工作的.目前我需要实现一种在代码块中看起来很乱的复杂排序函数,但它依赖于一些局部变量.例如:
foreach my $val (@values){
my @newArr = sort { $hash{$a}{$val}<=> $hash{$b}{$val} } @oldArr;
...
}
Run Code Online (Sandbox Code Playgroud)
但我们假设sort函数更复杂,因此它不能完全适合上面的代码.
如果我尝试使用一个函数(在for循环的范围内本地定义),我不断得到"在hash元素中使用未初始化的值".
我假设这是因为sub被解析一次,而不是为for循环的evry迭代重新创建.我试图了解如何实现每次迭代将重新解释的代码块,或者可能如何传递参数
由于某些原因,你没有显示有问题的代码,但我认为它是类似的
for my $val (@values) {
sub sort_func {
return $hash{$a}{$val} <=> $hash{$b}{$val};
}
my @newArr = sort sort_func @oldArr;
}
Run Code Online (Sandbox Code Playgroud)
我试图弄清楚这种机制是如何工作的.[...]我假设这是因为sub被解析一次,而不是为for循环的evry迭代重新创建.
不完全的.以下只解析和编译sub一次,但它有效:
for my $val (@values) {
my $cmp_func = sub {
return $hash{$a}{$val} <=> $hash{$b}{$val};
};
my @newArr = sort $cmp_func @oldArr;
}
Run Code Online (Sandbox Code Playgroud)
重要的$val是捕获的内容.$val在sub { ... }评估时捕获.记住这一点
sub foo { ... }
Run Code Online (Sandbox Code Playgroud)
在这方面与以下相同,
BEGIN { *foo = sub { ... }; }
Run Code Online (Sandbox Code Playgroud)
在我的代码中,它$val从foreach循环中捕获.在你的,它在编译时捕获,因此它捕获$val编译时存在的.这不是你想要的变量.
现在您已经知道如何使其工作,您可以根据需要将复杂代码移出(循环外).
sub make_cmp_func {
my ($hash, $val) = @_;
return sub {
return $hash->{$a}{$val} <=> $hash{$b}{$val};
};
}
for my $val (@values) {
my $cmp_func = make_cmp_func(\%hash, $val);
my @newArr = sort $cmp_func @oldArr;
}
Run Code Online (Sandbox Code Playgroud)
或者,您可以将必要的值传递给比较函数,而不是捕获它们.
sub cmp_func {
my ($hash, $val, $a, $b) = @_;
return $hash->{$a}{$val} <=> $hash{$b}{$val};
}
for my $val (@values) {
my @newArr = sort { cmp_func(\%hash, $val, $a, $b) } @oldArr;
}
Run Code Online (Sandbox Code Playgroud)
你想使用一个除了$a和之外还带参数的函数$b.
sub my_sort_func {
my ($val, $a, $b) = @_;
return $hash{$a}{$val} <=> $hash{$b}{$val};
}
foreach my $val (@values) {
my @newArr = sort { my_sort_func($val,$a,$b) } @oldArr;
...
}
Run Code Online (Sandbox Code Playgroud)
Perl使用代码块的机制sort有点特殊,并且不容易在纯Perl中复制.
根据暴徒的回答,这是"聪明但不一定聪明"的变种之一.如果您反对额外参数,则可以使用currying.
sub make_sorter {
my ($hashref, $val) = @_;
return sub {
$hashref->{$a}{$val} <=> $hashref->{$b}{$val}
};
}
for my $val (@values) {
my $sorter = make_sorter(\%hash, $val);
my @newArr = sort $sorter @oldArr;
}
Run Code Online (Sandbox Code Playgroud)
这在任何方面都不是更高效,更具可读性或更有价值,但在某些实际有用的地方了解该技术可能会很有趣.
| 归档时间: |
|
| 查看次数: |
3311 次 |
| 最近记录: |