为什么 "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.