perl - 为什么 "my @variable"在 sub 内并由 sub/sub 修改的行为如此奇怪

标签 perl scope subroutine

我有一个奇怪的行为(对于 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 ]

然后我读到类似命名子例程在符号表中定义一次,然后我做“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绑定(bind)到父子程序的“第一个”@x , 所以当 a第一次调用,b添加 1@x , 内外副本均指同一个版本。但是,第二次a被称为,一个新的@x创建了词法,但是 b仍然指向旧的,所以它增加了第二个 1到那个列表并打印它(内部),但是到了 a 的时候为了打印它的版本,它打印出(空的)全新的词汇(外部)。

匿名子程序不会出现这个问题,所以当你写 my $b = sub { ... } ,内@x总是指 a 的“当前”版本的词法@x .

关于perl - 为什么 "my @variable"在 sub 内并由 sub/sub 修改的行为如此奇怪,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41032063/

相关文章:

Fortran 子例程值关键字

regex - 除非在单引号引起来的字符串内,否则如何按空格分割字符串?

perl - 使用 Getopt::Long 解析参数的最简洁方法

perl - 如何通过多个键对 perl 哈希进行排序?

javascript - 将函数插入数组,将 let 转换为 var

arrays - 如何在子例程中传递数组的哈希值?

Perl,禁用缓冲输入

java - Maven - JDBC jar 文件的正确范围是什么?

javascript - 了解常见的 jQuery 插件样板

perl 子程序参数列表 - "pass by alias"?