具有函数闭包规则的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