2013-12-16 231 views
2

我试图理解use vars ($var);是如何工作的。我意识到,如果我想全局声明一个变量,我可以使用use vars ($var);或Perl 5.6和更高版本我可以使用our $var;在perl中声明全局变量

但是,我仍然只是试图了解它是如何工作的。看看the source,它看起来像你只是将该变量声明为一个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怎么做?

---------------- UPDATE ---------------

我简直复制你的代码完全相同,跑从test.cgi与use X;,而不是外壳...

X.pm

use strict; 
BEGIN { package X; no strict qw(refs); *main::x = \${"main::x"}; } 
print "Content-type: text/html\n\n"; # 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. 

是否在一个外壳,而不是在一个模块这只是工作的?

+0

不知道你添加的代码是假设要做的。 – ikegami

+0

我完全复制了你的代码,试着让它工作,因为我改变了上面。我的目标是让脚本在不使用'我们'或'使用变量'的情况下工作。我想了解这些代码如何工作并使其工作,但不行。它只能在这样的外壳中工作吗? – Jonathan

回答

3

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

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

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

1

简单地使用一个变量会将其创建为一个(全局)包变量。

$ 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. 

但是,为了保留它们的有用性,严格变量允许使用导入的变量而不会出错。

$ 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. 您等待整个脚本导入变量之前进行编译,所以进口发生经过严格的已经禁止该变量的引用。您需要通过使用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方法被调用。

+0

我在上面添加了代码,似乎仍然缺少一些东西。 – Jonathan