我有一个奇怪的行为(对Python程序员)子程序,简化如下:
use strict;
use Data::Dumper;
sub a {
my @x;
sub b { push @x, 1; print "inside: ", Dumper(\@x); }
&b;
print "outside: ", Dumper(\@x);
}
&a;
&a;
我发现结果是:
inside: $VAR1=[ 1 ]
outside: $VAR1 = [ 1 ]
inside: $VAR1=[1, 1]
outside: $VAR1= []
在调用&a
时我的想法是,@x
在" my @x
"之后是空数组并且在" &b
"之后有一个元素,然后死了。每次拨打&a
时,都是一样的。所以输出应该都是$VAR1 = [ 1 ]
。
然后我读了一些类似命名的子例程,在符号表中定义了一次,然后我做了#34; my $b = sub { ... }; &$b;
",这似乎对我有意义。
如何解释?
答案 0 :(得分:12)
根据“perlref”手册页:
命名子例程是在编译时创建的,所以它们是词法 变量[即,他们的'my'变量]被分配给父变量 来自第一次执行父块的词法。如果是父母 范围是第二次输入,其词法再次创建,而 嵌套的潜艇仍然引用旧的。
换句话说,一个已命名的子例程(您的b
)将其@x
绑定到父子例程的“第一个”@x
,因此当调用a
时第一次,b
将1
添加到@x
,内部和外部副本都引用同一版本。但是,第二次a
被调用时,会创建一个新的@x
词法,但b
仍然指向旧的词法,因此它会向该列表添加第二个1
并打印它(内部),但是当a
打印其版本时,它会打印出(空)全新的词法(外部)。
匿名子程序不会出现此问题,因此当您编写my $b = sub { ... }
时,内部@x
始终引用a
的词汇@x
的“当前”版本}。