Sna*_*ark 8 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");
}
Run Code Online (Sandbox Code Playgroud)
没有做我所期望的.
究竟发生了什么?(我希望它打印出来"test-0 \ntest-1 \ntest-2 \ntest-3 \ntest-4 \n")
Eri*_*rom 19
问题是sub name {...}构造不能像for循环中那样嵌套.
原因是因为一旦解析它们就会执行sub name {...}真正的手段BEGIN {*name = sub {...}}和开始块.所以子程序的编译和变量绑定发生在编译时,在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");
}
Run Code Online (Sandbox Code Playgroud)
打印
test-0
test-1
test-2
test-3
test-4
Run Code Online (Sandbox Code Playgroud)
据推测,在您的实际用例中,这些闭包将被加载到数组或散列中,以便以后可以访问它们.
您仍然可以使用带闭包的裸字标识符,但是您需要做一些额外的工作以确保在编译时名称可见:
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>"
Run Code Online (Sandbox Code Playgroud)
埃里克斯特罗姆的回答是正确的,也许你想看到的,但没有详细介绍绑定.
关于词汇生命周期的简短说明:词汇在编译时创建,甚至在输入范围之前实际可用,如此示例所示:
my $i;
BEGIN { $i = 42 }
print $i;
Run Code Online (Sandbox Code Playgroud)
此后,当它们超出范围时,它们将在下一次进入范围之前变为不可用:
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();
Run Code Online (Sandbox Code Playgroud)
在您的代码中,闭包$i在编译时绑定到初始词法.然而,foreach循环有点奇怪; 虽然my $i实际创建了一个词法,但foreach循环并没有使用它; 相反,它在每次迭代时将其别名为循环值之一,然后在循环之后将其恢复到其原始状态.因此,你的封闭是唯一引用原始词汇的东西$i.
略有变化表明更复杂:
foreach (@foo) {
my $i = $_;
sub printer {
my $blah = shift @_;
print "$blah-$i\n";
}
printer("test");
}
Run Code Online (Sandbox Code Playgroud)
这里,原始文件$i是在编译时创建的,并且闭包绑定到那个; 循环的第一次迭代设置它,但循环的第二次迭代创建一个$i与闭包无关的新关联.
| 归档时间: |
|
| 查看次数: |
479 次 |
| 最近记录: |