具有函数闭包规则的perl foreach循环
下面的代码具有函数闭包规则的perl foreach循环,perl,foreach,closures,Perl,Foreach,Closures,下面的代码 #!/usr/bin/env perl use strict; use warnings; my @foo = (0,1,2,3,4); foreach my $i (@foo) { sub printer { my $blah = shift @_; print "$blah-$i\n"; } printer("test"); } 没有达到我的期望 到底发生了什么? (我希望它打印出“test-0\ntest-1\n
#!/usr/bin/env perl
use strict;
use warnings;
my @foo = (0,1,2,3,4);
foreach my $i (@foo) {
sub printer {
my $blah = shift @_;
print "$blah-$i\n";
}
printer("test");
}
没有达到我的期望
到底发生了什么?
(我希望它打印出“test-0\ntest-1\ntest-2\ntest-3\ntest-4\n”)问题是
子名称{…}
构造不能像for
循环那样嵌套
原因是因为sub-name{…}
实际上意味着BEGIN{*name=sub{…}}
并且BEGIN块在解析后立即执行。因此,子例程的编译和变量绑定发生在编译时,for循环还没有运行
您要做的是创建一个匿名子例程,它将在运行时绑定其变量:
#!/usr/bin/env perl
use strict;
use warnings;
my @foo = (0,1,2,3,4);
foreach my $i (@foo) {
my $printer = sub {
my $blah = shift @_;
print "$blah-$i\n";
};
$printer->("test");
}
哪张照片
test-0
test-1
test-2
test-3
test-4
假设在您的实际用例中,这些闭包将被加载到数组或散列中,以便以后可以访问它们
您仍然可以在闭包中使用裸字标识符,但需要做一些额外的工作,以确保名称在编译时可见:
BEGIN {
for my $color (qw(red blue green)) {
no strict 'refs';
*$color = sub {"<font color='$color'>@_</font>"}
}
}
print "Throw the ", red 'ball'; # "Throw the <font color='red'>ball</font>"
开始{
对于我的$color(qw(红蓝绿)){
没有严格的“参考文献”;
*$color=sub{“@}
}
}
打印“扔球”,红色“球”;#“投球”
Eric Strom的回答是正确的,可能是您想要看到的,但没有详细介绍绑定
关于词法寿命的简要说明:词法是在编译时创建的,甚至在输入其作用域之前就可以使用,如本例所示:
my $i;
BEGIN { $i = 42 }
print $i;
此后,当它们超出范围时,它们将变得不可用,直到下一次进入范围:
print i();
{
my $i;
BEGIN { $i = 42 }
# in the scope of `my $i`, but doesn't actually
# refer to $i, so not a closure over it:
sub i { eval '$i' }
}
print i();
在代码中,闭包在编译时绑定到初始词法$i
。
然而,foreach循环有点奇怪;虽然my$i
实际上创建了一个词法,但foreach循环没有使用它;相反,它在每次迭代中将其别名为一个循环值,然后在循环后将其恢复到原始状态。因此,闭包是引用原始词法$i
的唯一对象
稍有变化则更为复杂:
foreach (@foo) {
my $i = $_;
sub printer {
my $blah = shift @_;
print "$blah-$i\n";
}
printer("test");
}
这里,原始的$i
是在编译时创建的,闭包绑定到它;循环的第一次迭代设置它,但是循环的第二次迭代创建了一个与闭包无关的新的$i