为什么 "my @variable" 在 sub 中并被 sub/sub 修改的行为如此奇怪
Why "my @variable" inside a sub and modified by sub/sub behaves so strange
我有一个奇怪的行为(对 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 ]
.
然后我读到类似命名子例程在符号 table 中定义一次的东西,然后我做“my $b = sub { ... }; &$b;
”,这对我来说似乎很有意义。
如何解释?
根据 "perlref" 手册页:
named subroutines are created at compile time so their lexical
variables [i.e., their 'my' variables] get assigned to the parent
lexicals from the first execution of the parent block. If a parent
scope is entered a second time, its lexicals are created again, while
the nested subs still reference the old ones.
换句话说,一个命名的子程序(你的 b
),有它的 @x
绑定到父子程序的 "first" @x
,所以当 a
第一次被调用,b
在@x
的基础上加了一个1
,内外拷贝都引用这个同一个版本。然而,第二次调用 a
时,创建了一个新的 @x
词法,但 b
仍然指向旧词法,因此它向该列表添加了第二个 1
并打印它(内部),但是当 a
打印其版本时,它会打印出(空的)全新词法(外部)。
匿名子程序不会出现这个问题,所以当你写 my $b = sub { ... }
时,内部的 @x
总是引用 a
的词法的 "current" 版本@x
.
我有一个奇怪的行为(对 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 ]
.
然后我读到类似命名子例程在符号 table 中定义一次的东西,然后我做“my $b = sub { ... }; &$b;
”,这对我来说似乎很有意义。
如何解释?
根据 "perlref" 手册页:
named subroutines are created at compile time so their lexical variables [i.e., their 'my' variables] get assigned to the parent lexicals from the first execution of the parent block. If a parent scope is entered a second time, its lexicals are created again, while the nested subs still reference the old ones.
换句话说,一个命名的子程序(你的 b
),有它的 @x
绑定到父子程序的 "first" @x
,所以当 a
第一次被调用,b
在@x
的基础上加了一个1
,内外拷贝都引用这个同一个版本。然而,第二次调用 a
时,创建了一个新的 @x
词法,但 b
仍然指向旧词法,因此它向该列表添加了第二个 1
并打印它(内部),但是当 a
打印其版本时,它会打印出(空的)全新词法(外部)。
匿名子程序不会出现这个问题,所以当你写 my $b = sub { ... }
时,内部的 @x
总是引用 a
的词法的 "current" 版本@x
.