"出口商","使用变量"和"本地"之间的互动

gcb*_*son 7 perl scope

我试图将此行为归结为最简单的测试用例.考虑以下两个模块:

Bar.pm

package Bar;

use base 'Exporter';
use vars qw/ $BarVar /;
BEGIN { @EXPORT_OK = qw/ $BarVar /; }

$BarVar = 'original';

1;
Run Code Online (Sandbox Code Playgroud)

Foo.pm

package Foo;

use Bar qw/ $BarVar /;

sub foo { print $BarVar . "\n"}

1;
Run Code Online (Sandbox Code Playgroud)

现在,以下脚本的输出 -

use strict;
use warnings;

use Foo;

{
  local $Bar::BarVar = 'modified'; 
  Foo::foo();
}

Foo::foo();
Run Code Online (Sandbox Code Playgroud)

是"原始"打印两次,我希望它被"修改"后跟"原始",因为我本来期望local声明$Bar::BarVar在整个范围内替换包变量,其中包括第一次调用foo().解释是什么?我怎样才能在当地覆盖$Bar::BarVar

ike*_*ami 9

您可能听过我说过myour创建变量(后者是别名),但这local只是对值进行临时备份.

我撒了谎.

local做备份,但没有价值.它备份相关标量的地址,创建新标量,并将名称与新标量相关联.在这种情况下,留下$Bar::BarVar引用新标量,并$Foo::BarVar引用旧标量.

$ perl -E'
   *x = \$y;  say \$x, " - ", \$y;
   local $y;  say \$x, " - ", \$y;
'
SCALAR(0x44d7c70) - SCALAR(0x44d7c70)
SCALAR(0x44d7c70) - SCALAR(0x44ba130)
Run Code Online (Sandbox Code Playgroud)

如果您实际上只是备份值,问题就会消失.

use Sub::ScopeFinalizer qw( scope_finalizer );

{
   my $backup = $Bar::BarVar;
   my $guard = scope_finalizer { $Bar::BarVar = $backup };
   $Bar::BarVar = 'modified'; 
   Foo::foo();
}
Run Code Online (Sandbox Code Playgroud)

可能存在更专业的工具.