kjo*_*kjo 5 perl closures perl5
注意:这个问题中的闭包只是一个方便的例子; 我实际使用的那个比这复杂得多.IOW,请忽略这个关闭的细节; 重要的是AFAICT,它指的是父范围内的词汇变量.
我想重新定义foo下面的sub ,以便调用中的第一个参数List::Util::reduce替换为对嵌套闭包的引用.
use strict;
use warnings FATAL => 'all';
use List::Util;
sub foo {
my ( $x, $y ) = @_;
return List::Util::reduce { $y->[ $b ]{ $x } ? $a + ( 1 << $b ) : $a } 0, 0 .. $#$y;
}
Run Code Online (Sandbox Code Playgroud)
我的第一次尝试是这样的:
sub foo {
my ( $x, $y ) = @_;
sub z {
our ( $a, $b );
return exists $y->[ $b ]{ $x } ? $a | ( 1 << $b ) : $a;
}
return List::Util::reduce \&z, 0, 0 .. $#{ $y };
}
Run Code Online (Sandbox Code Playgroud)
......但这会导致警告说Variable "$y" will not stay shared.
我以前见过这种错误,我唯一知道的方法是sub用分配给变量的匿名子替换嵌套定义.因此,我尝试了这个:
sub foo {
my ( $x, $y ) = @_;
my $z = sub {
our ( $a, $b );
return exists $y->[ $b ]{ $x } ? $a | ( 1 << $b ) : $a;
};
return List::Util::reduce( $z, 0, 0 .. $#{ $y } );
}
Run Code Online (Sandbox Code Playgroud)
现在错误说Type of arg 1 to List::Util::reduce must be block or sub {} (not private variable).
这个我真的不明白.为什么将subref作为第一个参数传递给reduce不支持?
PS:以下工作:
sub foo {
my ( $x, $y ) = @_;
my $z = sub {
our ( $a, $b );
return exists $y->[ $b ]{ $x } ? $a | ( 1 << $b ) : $a;
};
return List::Util::reduce { $z->( $a, $b ) } 0, 0 .. $#{ $y };
}
Run Code Online (Sandbox Code Playgroud)
...但我真的想知道(a)使用subref作为第一个参数List::Util::reduce有什么问题(例如,是否存在支持这种变体的技术障碍?); (b)是否有更直接的方法(而不是{ $z->( $a, $b ) })传递给List::Util::reduce嵌套的封闭?
reduce有一个原型&@。这意味着调用必须使用以下语法之一:
reduce BLOCK LIST
reduce sub BLOCK, LIST # The first form is short for this.
reduce \&NAME, LIST
reduce \&$NAME, LIST # Same as third form, but via reference (short form)
reduce \&BLOCK, LIST # Same as third form, but via reference (long form)
Run Code Online (Sandbox Code Playgroud)
您可以使用以下任何等效语句:
return reduce { exists $y->[ $b ]{ $x } ? $a | ( 1 << $b ) : $a } 0, 0 .. $#$y;
Run Code Online (Sandbox Code Playgroud)
# Long way of writing the first.
return reduce(sub { exists $y->[ $b ]{ $x } ? $a | ( 1 << $b ) : $a }, 0, 0 .. $#$y);
Run Code Online (Sandbox Code Playgroud)
my $z = sub { exists $y->[ $b ]{ $x } ? $a | ( 1 << $b ) : $a };
return reduce(\&$z, 0, 0 .. $#$y);
Run Code Online (Sandbox Code Playgroud)
您还可以选择覆盖原型。
my $z = sub { exists $y->[ $b ]{ $x } ? $a | ( 1 << $b ) : $a };
return &reduce($z, 0, 0 .. $#$y);
Run Code Online (Sandbox Code Playgroud)