Perl中my关键字的函数作用域问题:两段代码行为差异疑惑
Perl嵌套子例程作用域差异解析
这是个非常典型的Perl作用域问题,核心在于Perl对嵌套子例程的变量绑定是在编译阶段确定的,而非运行时,咱们一步步拆解两个代码段的行为:
代码段1分析
$x = 8; # 全局包变量 $main::x sub a { sub b { print "B: $x\n"; } # 编译sub a时,优先处理sub b的定义 my $x = 3; # 运行时才创建词法变量$x &b(); } &a();
当Perl编译sub a的代码时,会先处理内部的sub b定义。此时,sub b里的$x会去查找当前作用域中已存在的词法变量——但my $x = 3这条声明在sub b的定义之后,编译到sub b时还没识别到这个词法变量,所以Perl会把$x解析为全局包变量$main::x。
等到运行时,虽然sub a里创建了词法$x=3,但sub b的变量绑定已经在编译时固定了,所以调用&b()时会输出全局变量的8。
代码段2分析
$x = 8; # 全局包变量 $main::x sub a { my $x = 3; # 编译时先识别到这个词法变量的作用域 sub b { print "B: $x\n"; } # 此时编译sub b,$x会绑定到已声明的词法变量 &b(); } &a();
这次my $x = 3的声明在sub b定义之前,当Perl编译sub a时,先处理my $x的声明,标记出这个词法变量的作用域。接下来编译sub b时,里面的$x就会绑定到这个已存在的词法变量上。
运行时调用&b(),自然会输出词法变量的3。
关键总结
Perl的子例程定义(包括嵌套的)是在编译阶段处理的,变量绑定也是在这个阶段确定的,和运行时的执行顺序无关。如果嵌套子例程定义在词法变量声明之前,它就看不到这个词法变量,会回退使用全局包变量;反之则会绑定到词法变量。
另外补充个小细节:如果多次调用&a(),sub b只会被定义一次(第二次定义会触发警告),因为它的编译是一次性完成的。
内容的提问来源于stack exchange,提问作者gokhansim
相关产品推荐
相关产品推荐

