我试图将这种行为归结为最简单的测试用例。考虑以下两个模块:
酒吧.pm
package Bar;
use base 'Exporter';
use vars qw/ $BarVar /;
BEGIN { @EXPORT_OK = qw/ $BarVar /; }
$BarVar = 'original';
1;
Foo.pm
package Foo;
use Bar qw/ $BarVar /;
sub foo { print $BarVar . "\n"}
1;
现在,以下脚本的输出 -
use strict;
use warnings;
use Foo;
{
local $Bar::BarVar = 'modified';
Foo::foo();
}
Foo::foo();
是“original”打印了两次,我希望它被“modified”后跟“original”,因为我希望用 local
声明来替换包变量 $Bar::BarVar
贯穿其整个范围,其中包括对 foo()
的第一次调用。有何解释?如何在本地覆盖 $Bar::BarVar
?
最佳答案
您可能听过我说过 my
和 our
创建变量(后者是别名),但是 local
只是使该值的临时备份。
我撒谎了。
local
确实进行了备份,但没有备份值(value)。它备份关联标量的地址,创建一个新标量,并将名称与新标量关联起来。在这种情况下,$Bar::BarVar
引用新标量,$Foo::BarVar
引用旧标量。
$ perl -E'
*x = \$y; say \$x, " - ", \$y;
local $y; say \$x, " - ", \$y;
'
SCALAR(0x44d7c70) - SCALAR(0x44d7c70)
SCALAR(0x44d7c70) - SCALAR(0x44ba130)
如果您实际上只备份该值,问题就会消失。
use Sub::ScopeFinalizer qw( scope_finalizer );
{
my $backup = $Bar::BarVar;
my $guard = scope_finalizer { $Bar::BarVar = $backup };
$Bar::BarVar = 'modified';
Foo::foo();
}
可能存在更专业的工具。
关于perl - 'Exporter'、 'use vars' 和 'local' 之间的交互,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31864081/