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

酒吧

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();


是“原始”打印两次,我希望它会被“修改”,然后是“原始”,因为我希望local声明在整个范围内替换包变量$Bar::BarVar,其中包括首先调用foo()。有什么解释?如何在本地覆盖$Bar::BarVar

最佳答案

您可能已经听过我说过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)


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

use Sub::ScopeFinalizer qw( scope_finalizer );

{
   my $backup = $Bar::BarVar;
   my $guard = scope_finalizer { $Bar::BarVar = $backup };
   $Bar::BarVar = 'modified';
   Foo::foo();
}


可能存在更专业的工具。

09-25 21:53