在perl中声明全局变量



我试图了解use vars ($var);是如何工作的。我意识到,如果我想全局声明一个变量,我可以使用use vars ($var);或Perl5.6或更高版本,我可以用our $var;

然而,我仍在努力了解它是如何工作的。从源代码来看,您只需将变量声明为typeglob,并将其设置为自身的引用版本。什么!?

# My_Module.pm
use strict (vars, subs);
use CGI::Carp;
*My_Module::My_Global = $My_Module::My_Global;
sub my_function {
  $My_Global = 'Am I declared?';
}

现在这不起作用,我显然得到了一个"未定义的符号"错误。那么use vars是如何做到的呢?

----------------更新----------------

我完全复制了你的代码,用use X;而不是shell从test.cgi运行它。。。

X.pm

use strict;
BEGIN { package X; no strict qw( refs ); *main::x = ${"main::x"}; }
print "Content-type: text/htmlnn"; # I added this line since not printing to shell
$x = 123; say $x;
1; 

test.cgi

#!/usr/bin/perl
use strict;
use X;

我得到了和以前一样的编译错误:

Global symbol "$x" requires explicit package name at X.pm line 4.

这只适用于外壳而不适用于模块吗?

为typeglob指定引用是一种特殊的赋值;它只将引用类型的typeglob的一部分替换为引用。此外,vars对变量名使用了符号引用,而您没有使用符号引用。use vars也在不同的包中执行,并且在编译时执行,而不是在运行时执行。内联等价物是:

BEGIN { package foo; *My_Module::My_Global = ${"My_Module::My_Global"} }

也就是说,使用全局变量通常是个坏主意。使用不再受支持的perl版本同样是个坏主意。

只需使用一个变量即可将其创建为(全局)包变量。

$ perl -wE'$x = 123; say $x;'
123

这是非常危险的,所以程序员告诉Perl使用use strict qw( vars );来禁止这种情况。

$ perl -wE'use strict; $x = 123; say $x;'
Global symbol "$x" requires explicit package name at -e line 1.
Global symbol "$x" requires explicit package name at -e line 1.
Execution of -e aborted due to compilation errors.

然而,为了保持它们的有用性,严格的vars允许在没有错误的情况下使用导入的变量。

$ perl -wE'use strict; say $Config{version};'
Global symbol "%Config" requires explicit package name at -e line 1.
Execution of -e aborted due to compilation errors.
$ perl -wE'use strict; use Config qw( %Config ); say $Config{version};'
5.18.1

use vars只是创建一个新的变量并将其导出


虽然您的代码即将做到这一点,但它存在两个问题。

  1. 至关重要的是,在代码中遇到对变量的任何引用之前导入变量。需要做两个更改才能在代码中修复此问题。

    1. 赋值的操作数必须在计算该赋值之前进行编译,因此在代码引用变量之前,您的赋值不可能导入该变量。

      *Package::foo = $Package::foo;      # XXX Compile-time lookup
      *Package::foo = ${"Package::foo"};  # Runtime looup
      *Package::foo = ( my $anon );      # Would work too.
      
    2. 在导入变量之前,您需要等待整个脚本的编译,因此导入发生在strict已经禁止对变量的引用之后。您需要使用BEGIN { }[1]更快地执行导入。

  2. 对于要被视为已导入的变量,执行导出的代码必须在与要将变量导出到的包不同的包中编译。

如果我们应用这些修复,我们最终会得到以下结果:

$ perl -wE'
   use strict;
   BEGIN { package X; no strict qw( refs ); *main::x = ${"main::x"}; }
   $x = 123; say $x;
'
123

注:

  1. 请记住

    use Module qw( ... );
    

    与基本相同

    BEGIN { require Module; Module->import(qw( ... )); }
    

    换句话说,在解析任何进一步的代码之前,执行模块并调用其import方法。

相关内容

  • 没有找到相关文章

最新更新