【问题标题】:Local and Global variables in perlperl 中的局部变量和全局变量
【发布时间】:2013-10-06 15:55:48
【问题描述】:

我对 Perl 中的 local/our 范围几乎没有疑问。我阅读了很多文档,但我仍然很困惑。以下是困惑

  1. local 范围是什么?

    我读的是->本地复制全局变量的值,更改值,用户将使用它,在块之外它将保留全局值

    Confusion -> my 做同样的事情。我看到的唯一好处是,像$package::var 这样的一些变量不能用我的范围声明,但可以用本地范围声明。本地还有什么

  2. 什么是“全局”变量?

读取的是 -> 它的范围在包内。基本上我们将全局变量放在@EXPORT 数组中并使用它或附加命名空间以在其他包中使用。

doubt -> 同样,如果我们在 main 中声明具有 my 范围的变量,那么我们可以在整个包中访问该变量。那正确吗?是否可以在@EXPORT 数组中添加my 范围变量并在其他包中使用它?

我认为全局变量是用our 关键字声明的。还有其他方法吗?

这个问题可能看起来重复,但我很困惑。

【问题讨论】:

  • 凯文:如何强调这一点。像我一样,我们所有的键盘都是亮点
  • 在单词周围加上单引号 (`) 以突出显示。
  • 关于 Perl 变量作用域的问题可能有点重复,但它非常重要。 Perl 变量非常难以理解。这在很大程度上与 Perl 的悠久历史有关,因为它从单纯的 awksh 的替代品转变为完全面向对象的语言。曾经,所有变量都是包变量,local 是您限制其范围的方式。现在,我们有了三种不同的变量类型(不要忘记state!),而这个local 函数实际上并不能生成局部变量。

标签: perl scope


【解决方案1】:

有两种变量,词法作用域和全局作用域。

在版本 5 之前的 Perl 中,只有全局范围。这些变量是包变量。如果您使用包前缀,这些变量在程序中的任何地方都可用。

引入local 关键字是为了提供一种在有限范围内(例如在一个子例程内)更改这些包全局变量之一的值的方法。当使用local 语句进入作用域时,它将旧值保存在堆栈中,退出时,它将恢复旧值。这些仍然是包全局变量,这意味着它们仍然可以在任何地方使用。如果您在具有local 变量的范围内,并且您调用了一个子例程,则该变量在该子例程中仍然可见。

my 关键字是在版本 5 中引入的,它提供了词法范围的变量。这些变量只存在于声明它们的范围内。这意味着如果你调用一个子程序,my 变量是不可见的。退出作用域后,my 变量就会消失。您应该尽可能使用my 变量,因为您不希望您的变量在您调用的子例程中可见。您不能在 @EXPORT 列表中使用这些类型的变量,因为这些变量在其范围之外是不可见的。

最后,our 关键字是两者的组合,因为它为您提供了一个包全局变量,但该变量是词法范围的。这意味着它可以在程序中的任何地方使用,但在封闭块的末尾,您不能再引用该变量。

【讨论】:

  • 为什么本地被称为动态作用域
  • local 变量的范围取决于运行时发生的情况。变量的范围从local 行开始,到封闭块的末尾结束,但该变量的范围还包括在其间调用的所有子例程。相比之下,my 变量具有静态范围,因为它不会根据运行时发生的情况而改变。
  • 请添加示例
【解决方案2】:

就作用域而言,Perl 中有两种变量。

  • 词法变量是词法范围的,这意味着它们仅在当前词法范围内可见。
  • 包变量是全局范围的,这意味着它们对解释器中的所有代码都是可见的。

以下是创建变量的方法。

  • my 创建一个词法变量。
  • our 创建一个词法变量,该变量别名为当前包中的同名变量。换言之,our $foo;alias my $foo = $The::Current::Package::foo; 相同。
  • 全局变量是在使用时创建的。

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 的功能,用于无法以其他方式在词法上声明的变量。

(从历史上看,这都是变量。从 5.6 开始,只有标点符号变量不能在词法上声明。)


什么是“全局”变量?

全局可见的变量,即解释器中的任何代码。


是否可以在 @EXPORT 数组中添加 my 作用域变量并在其他包中使用它?

没有。 @EXPORT 由出口商使用。导出器只能找到全局符号(因为文件是在新的词法范围内编译的),所以 @EXPORT 只能包含全局符号。

【讨论】:

  • 'ikegami' :除了范围之外,'local' 和 'my' 基本上是相同的。 'my' 无法访问,如您在 foo() 中所示,但本地工作在那里。有没有我们使用“本地”的真实实际场景
  • 为什么本地被称为动态作用域
  • 不,这是完全错误的。只有符号有作用域,没有局部变量这样的东西。正如我已经说过的,local $_;,因为你不能这样做my $_;
  • 因为如果你忽略了变量在local 的范围退出后不会停止存在的事实,那么它就是一个名称。
  • @Nitesh 有很多真实、实用的场景可以使用local。一个常见的例子是reading a file into a scalar
【解决方案3】:

示例 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() 范围内看到,并且可以在从其myfunc() 范围内调用的任何函数的范围内看到。

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

【讨论】:

    【解决方案4】:

    这是我发现的关于变量作用域的内容:

    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";
     }
    

    【讨论】:

    • 这是一个有用的答案,带有很好的解释性代码。我已经对其进行了投票和编辑,以从程序代码中删除行号,修复拼写错误,为 Perl 关键字添加代码格式。
    猜你喜欢
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 2019-04-04
    • 2012-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多