perl中的局部变量和全局变量

a6b3iqyw  于 2022-11-15  发布在  Perl
关注(0)|答案(4)|浏览(262)

我对Perl中的local/our作用域没有什么疑问。我读了很多文档,但我仍然感到困惑。以下是困惑之处
1.什么是local作用域?
我读到的是-〉local复制全局变量的值,更改该值,用户将使用它,在块之外,它将保留全局值
混乱-〉my做了同样的事情。我看到的唯一好处是一些变量,如$package::var,不能用我的作用域声明,但可以用局部作用域声明。
1.什么是“全局”变量?
我读到的是-〉它的作用域在包内,基本上我们把全局变量放在@EXPORT数组中,然后使用它,或者把它附加到命名空间中,以便在其他包中使用。
我怀疑-〉如果我们只在main中声明my作用域的变量,那么我们就可以在整个包中访问该变量。是这样吗?有没有可能在@EXPORT数组中添加my作用域的变量,然后在其他包中使用它?
我认为全局变量是用our关键字声明的。有没有其他的方法可以这样做?
这个问题可能看起来重复,但我很困惑。

bzzcjhmw

bzzcjhmw1#

就作用域而言,Perl中有三种类型的变量。

  • 词法变量是按词法作用域划分的,这意味着它们只在当前词法作用域(基本上是文件或块)中可见。
  • 另一方面,包变量可以在解释器中的任何地方使用它们的限定形式(例如$Foo::x),并且它们可以由共享变量包的任何代码在没有限定的情况下使用。
  • 某些程序包变量在解释器中的任何位置都是可见的,而不需要进行限定。这些变量包括标点符号变量和一些命名变量,如@ARGVSTDOUT。例如,$x在程序包Foo中表示$Foo::x,在程序包Bar中表示$Bar::x(假设作用域中没有名为$x的词法变量),但$_始终引用$::_

当不再引用变量时,变量将被销毁。

  • 词法变量通常在退出词法作用域时被销毁。
  • 包变量通常在程序退出时被销毁。

以下是创建变量的几种方法。

  • mystate创建词法变量。
  • our创建一个词法变量,该变量的别名与当前包中的变量同名。换句话说,our $x;等效于包Foo中的my \$x = \$Foo::x;
  • 包变量在使用时创建。

local不会创建任何变量,它只是备份一个变量,直到当前词法作用域被破坏为止,它会从此时的备份值中恢复。
my执行相同的操作。
local并不改变变量的作用域。虽然词法变量只在词法作用域中可见,但本地化包变量在整个解释器中仍然可见。

$x = 123;
sub foo { print "$x\n"; }
{ local $x = 456; foo(); }  # 456
foo();                      # 123
$x = 123;
sub foo { print "$x\n"; }
{ my $x = 456; foo(); }   # 123
foo();                    # 123

local还有什么
local主要用于近似my的功能,以用于无法以其他方式以词法方式声明的变量。
从Python 5.6开始,只有标点符号变量不能用词法声明。
什么是“全局”变量?
全局变量是可以全局看到的变量。
所有包变量都可以被解释器中的任何代码看到,因此它们都是全局变量。
要从其他软件包中查看它们,您需要限定它们。$x$Foo::x是同一个变量吗?
对某些人来说,全局变量指的是你可以使用的包变量的集合。这意味着package改变了全局变量的集合。由于package指令通常是在文件的基础上使用的,这意味着文件级的词法也是有效的全局定义。有时候它们确实被称为全局变量。
但是如果package改变了全局变量的集合,那么它们就不是真正的全局变量了,对吗?有些人也是这样想的,他们只认为标点变量(例如$_)和少数可以在任何地方非限定使用的命名变量(*::STDOUT)是全局变量。
简而言之,这是一个相当无用的术语。
有没有可能在@EXPORT数组中添加我的作用域变量,并在其他包中使用它?
不可以。@EXPORT是由Exporter使用的。Exporter除了包符号之外什么都找不到(因为文件是在fresh lexical scope中编译的),所以@EXPORT必须只包含包符号。

rlcwz9us

rlcwz9us2#

有两种类型的变量:词法作用域变量和全局作用域变量。
在Perl版本5之前,只有全局作用域。这些变量是包变量。如果使用包前缀,这些变量在程序中的任何地方都可用。
关键字local的引入是为了提供一种在有限的作用域(例如子例程)内改变这些包全局变量的值的方法。当使用local语句进入作用域时,它会将旧值保存在堆栈中,而在退出时,它会恢复旧值。这些仍然是包全局变量。这意味着它们仍然在任何地方都可用。如果你在一个带有local变量的作用域中,并且你调用了一个子例程,那么这个变量在那个子例程中仍然是可见的。
my关键字是在版本5中引入的,它提供了词法作用域变量。这些变量只存在于声明它们的作用域中。这意味着如果你调用一个子例程,my变量是不可见的。一旦退出一个作用域,my变量就消失了。如果可能的话,你应该更喜欢使用my变量。因为您不希望您的变量在您调用的子程序中可见。您不能在@EXPORT列表中使用这些类型的变量,因为这些变量在其作用域之外不可见。
最后,our关键字是两者的结合,因为它提供了一个包全局变量,但该变量是词法作用域的。这意味着它在程序的任何地方都可用,但在封闭块的末尾,您不能再引用该变量。

vdgimpew

vdgimpew3#

下面是我对变量作用域的发现:
如果在块内部使用,my声明是非常清楚和直接的。如果在任何块外部的main中使用,它们会有一点不同,这意味着在块外部声明的my变量即使在从同一文件中的任何位置调用的函数内部也是可见的,只要这些函数是在同一文件中定义的。如果在块内部声明,尽管,即使从同一个块中调用,它们对函数也是不可见的。所有my变量似乎都位于堆栈中。并且:不能使用local对它们进行本地化。
our变量存在于堆中。即使你有一个同名的my变量,我们的变量仍然可以通过${'var'}访问,它在符号表中查找一个同名的变量并取消引用它。另一方面,my变量没有符号表条目。
在我看来,local变量就像是以前Perl版本的遗物。它们只是块作用域的全局(our)变量的重新赋值,并在块终止后恢复它们以前的值。我看不出使用它们有什么真实的意义。
我下面的小程序展示了这一切,它展示了除了众所周知的defined()测试之外,如何严重地缺少declared()测试来识别未声明的变量。

#!/usr/bin/perl

 use strict;

 ### This is about variable scoping with my, our and local
 my $fsv = "file scope";                 # visible for all code in this file
 our $gsv = "global scope";              # not different from my $fsv, except in packages
 our $lsv = "global";                    # global scope, but localized in subsequent block

 {
    my $bsv = "lex scope";               # visible only inside this block, not even in subs called from here
    $gsv = "visible everywhere";
    local $lsv = "global, but localized val";

    print "This is variable \$bsv with value $bsv inside block\n";
    print "This is variable \$fsv with value $fsv inside block\n";
    print "This is variable \$lsv with value $lsv inside block\n\n";
    print_vars("calledfromblock");
 }

 print_vars("calledfromoutside");

 no strict 'vars';                       # needed if testing variable for declaredness rather than definedness
 if ( defined $bsv ) {
    print "\$bsv as defined outside braces: $bsv\n"
 } else {
    print "\$bsv not defined outside braces\n";
 }
 print "This is variable \$lsv with value $lsv outside block\n";
 # use strict 'vars';                    # no strict 'vars' effective even in sub print_vars unless switched back on

 sub print_vars
 {
    my $whence = shift;
    my $gsv = "my variable";
    no strict 'refs';                    # needed to access the global var $gsv using ${'gsv'} despite the my declaration

    if ( $whence eq "calledfromblock" ) {
       print "\t print_vars called from within the block:\n";
       ( defined $bsv )     ? print "\$bsv is $bsv inside sub\n"     : print "\$bsv not defined inside sub\n";
       ( defined $fsv )     ? print "\$fsv is $fsv inside sub\n"     : print "\$fsv not defined inside sub\n";
       ( defined ${'gsv'} ) ? print "\$gsv is ${'gsv'} inside sub\n" : print "\$gsv not defined inside sub\n";
       ( defined ${'lsv'} ) ? print "\$lsv is ${'lsv'} inside sub\n" : print "\$lsv not defined inside sub\n";
    } else {
       print "\t print_vars called from outside the block:\n";
       ( defined $bsv ) ? print "\$bsv is $bsv inside sub\n" : print "\$bsv not defined inside sub\n";
       ( defined $fsv ) ? print "\$fsv is $fsv inside sub\n" : print "\$fsv not defined inside sub\n";
       ( defined $gsv ) ? print "\$gsv is $gsv inside sub\n" : print "\$gsv not defined inside sub\n";
       ( defined $lsv ) ? print "\$lsv is $lsv inside sub\n" : print "\$lsv not defined inside sub\n";
    }
    print "\n";
 }
wxclj1h5

wxclj1h54#

示例1:

sub mess_with_foo {
    $foo=0;
}

sub myfunc {
    my $foo=20;
    mess_with_foo();
    print $foo;
}
myfunc();

示例2:

sub mess_with_foo {
    $foo=0;
}

sub myfunc {
    local $foo=20;
    mess_with_foo();
    print $foo;
}
myfunc();

范例1会打印20,因为mess_with_foo()无法看见my $foo。它无法变更它。my $foo只能在myfunc()的范围内看见。
范例2会打印0,因为mess_with_foo()可以看见my $foo并加以变更。local $foo可以在其myfunc()的范围AND中看见,而且可以在从其myfunc()的范围内呼叫的任何函式范围中看见。

这是唯一的区别。my $foolocal $foo都不会出现在它们的myfunc()范围之外。

相关问题