以下代码

#!/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”)

最佳答案

问题在于,不能像sub name {...}循环中那样嵌套for构造。

原因是因为sub name {...}实际上意味着BEGIN {*name = sub {...}}和begin块在解析后就立即执行。因此,子例程的编译和变量绑定(bind)发生在编译时,而for循环才有机会运行。

您要做的是创建一个匿名子例程,该例程将在运行时绑定(bind)其变量:

#!/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>"

10-08 12:08