- 论坛徽章:
- 0
|
这可能是perl的一个小bug,但是也可以看做不是。
普通的sub在运行前只编译一次,而匿名sub的每次调用都会重新编译。后者在作为closure使用的时候,应该在每次调用的时候取所在环境中的变量的值——类似于静态变量。
但从这个程序看来,运行阶段,f中的closure只取了所在sub的“可见”的变量,对于f可见的$x没有保留。也就是说,虽然f可以看见$x,但是由于在f中并没有提到$x,所以里面的closure在运行的时候就成了没有初始化的$x. 这在编译中通过了,不会报错,但是在运行中就出现了未预料的结果。
解决方法1,可以像3楼提到的,在{}前增加BEGIN,确保在加载阶段就正确初始化;
解决方法2,在f中“提及”一下闭包使用的变量,如下代码就可得到预期的结果:
use strict;
use warnings;
{
my $x = 'A';
sub f {
my $y = $x; #提一下$x,让closure看到。$y is useless。
sub { $x++ }
}
sub g { sub { $x++ } if $x }
}
my $F=f();
my $G=g();
print $F->(),$G->(),"," for 1..4;
其实,g和f的区别,就是g里面提到了$x,而在f中是隐含看到$x的。
实验验证:
1.不提及变量,结果为未初始化use strict;
use warnings;
{
my $x = 'A'; #给 g 所用
my $y = '5'; #给 f 所用
sub f {
sub {
print "<",$y++,">"; #第一次运行时,closure看不见$y,只能取0初始化;
$y # 返回值为$y+1
}
}
sub g { sub { $x++ } if $x }
}
my $F=f();
my $G=g();
print $F->(),$G->(),"," for 1..4; #打印结果:<0>1A,<1>2B,<2>3C,<3>4D,
2。提及变量,结果正常。
use strict;
use warnings;
{
my $x = 'A';
my $y = '5';
sub f {
my $z = $y; #提一下$y,让closure看到。
sub {
print "<",$y++,">";
$y
}
}
sub g { sub { $x++ } if $x }
}
my $F=f();
my $G=g();
print $F->(),$G->(),"," for 1..4; # 打印: <5>6A,<6>7B,<7>8C,<8>9D,
[ 本帖最后由 royalzhang 于 2007-9-21 14:57 编辑 ] |
|