【问题标题】:What is the difference between my and local in Perl?Perl 中的 my 和 local 有什么区别?
【发布时间】:2010-09-12 21:03:24
【问题描述】:

我看到这两个脚本都在我试图调试的脚本中使用,但文献还不清楚。谁能帮我揭开这个谜底?

【问题讨论】:

    标签: perl scoping


    【解决方案1】:

    简短的回答是my 在词法范围内将变量标记为私有,而local 在动态范围内将变量标记为私有。

    my 更容易理解,因为它创建了通常意义上的局部变量。创建了一个新变量,它只能在封闭的词法块内访问,通常用花括号标记。花括号规则有一些例外,例如:

    foreach my $x (@foo) { print "$x\n"; }
    

    但这只是 Perl 做你的意思。通常你有这样的东西:

    sub Foo {
       my $x = shift;
    
       print "$x\n";
    }
    

    在这种情况下,$x 是子例程私有的,它的作用域由花括号括起来。需要注意的是,这与local 形成对比的是,my 变量的范围是根据您在文件中写入的代码定义的。这是一种编译时现象。

    要理解local,您需要考虑程序运行时的调用堆栈。当变量为local 时,它会从local 语句对堆栈上低于该变量的所有内容执行的点重新定义,直到您将堆栈返回到包含local 的块的调用者。

    一开始可能会让人感到困惑,因此请考虑以下示例。

    sub foo { print "$x\n"; }
    sub bar { local $x; $x = 2; foo(); }
    
    $x = 1;
    foo(); # prints '1'
    bar(); # prints '2' because $x was localed in bar
    foo(); # prints '1' again because local from foo is no longer in effect
    

    第一次调用foo 时,它会看到$x 的全局值为1。当调用bar 并运行local $x 时,会重新定义堆栈上的全局$x。现在,当从bar 调用foo 时,它会看到$x 的新值2。到目前为止,这并不是很特别,因为如果不调用local,也会发生同样的事情。神奇的是,当bar 返回时,我们退出由local $x 创建的动态作用域,而之前的全局$x 又回到作用域中。所以对于foo的最终调用,$x是1。

    您几乎总是希望使用my,因为它会为您提供您正在寻找的局部变量。千载难逢,local 做很酷的事情真的很方便。

    【讨论】:

      【解决方案2】:

      动态范围。这是一个简洁的概念。许多人不使用它,也不理解它。

      基本上将 my 视为创建变量并将其锚定到 {} 的一个块,A.K.A.范围。

      my $foo if (true); # $foo lives and dies within the if statement.
      

      所以my 变量是你习惯的。而使用动态作用域 $var 可以在任何地方声明并在任何地方使用。 因此,使用local,您基本上可以暂停使用该全局变量,并使用“局部值”来处理它。所以local 为一个临时变量创建了一个临时作用域。

      $var = 4;
      print $var, "\n";
      &hello;
      print $var, "\n";
      
      # subroutines
      sub hello {
           local $var = 10;
           print $var, "\n";
           &gogo; # calling subroutine gogo
           print $var, "\n";
      }
      sub gogo {
           $var ++;
      }
      

      这应该打印出来:

      4
      10
      11
      4
      

      【讨论】:

      • 你没有调用子程序。
      • 不要有条件地声明词法变量:它具有未定义的行为。
      【解决方案3】:

      引用Learning Perl:

      但是 local 被错误命名,或者至少是误导性的命名。我们的朋友 Chip Salzenberg 说,如果他有机会乘坐时光机回到 1986 年并给拉里一条建议,他会告诉拉里用“save”这个名字来称呼本地人。 [14]那是因为 local 实际上会将给定的全局变量的值保存起来,所以它稍后会自动恢复到全局变量。 (没错:这些所谓的“局部”变量实际上是全局变量!)这种保存和恢复机制与我们现在已经见过两次的机制相同,分别在 foreach 循环的控制变量和 @_子程序参数数组。

      所以,local 保存全局变量的当前值,然后将其设置为某种形式的空值。您经常会看到它用于吞食整个文件,而不是仅引导一行:

      my $file_content;
      {
          local $/;
          open IN, "foo.txt";
          $file_content = <IN>;
      } 
      

      调用local $/ 将输入记录分隔符(Perl 停止读取“行”处的值)设置为空值,导致宇宙飞船操作员读取整个文件,因此它永远不会碰到输入记录分隔符。

      【讨论】:

        【解决方案4】:

        我不敢相信没有人与 Mark Jason Dominus 的详尽论文有关:

        【讨论】:

        • 警告词:这两篇文章都很老了,第二篇(作者自己警告)已经过时了。它演示了在现代版本的 Perl 中已被词法文件句柄取代的文件句柄本地化技术。
        • 正如克林顿在写第一篇文章时是(美国)总统
        【解决方案5】:

        http://perldoc.perl.org/perlsub.html#Private-Variables-via-my()

        与创建的动态变量不同 局部运算符,词法变量 用我的声明完全隐藏 来自外部世界,包括任何 称为子程序。这是真的,如果 这是同一个子程序调用 它自己或其他地方——每个电话都得到 它自己的副本。

        http://perldoc.perl.org/perlsub.html#Temporary-Values-via-local()

        本地修改其列出的变量 成为封闭块的“本地”, eval,或者做 FILE --and 到任何 从里面调用的子程序 堵塞。当地人只是给临时的 全局值(意思是包) 变量。它不会创建本地 多变的。这被称为动态 范围界定。词法作用域是用 my, 更像 C 的 auto 声明。

        我认为这一点都不清楚,除了说“本地到封闭块”之外,它的意思是当块退出时恢复原始值。

        【讨论】:

          【解决方案6】:

          Google 在这方面真的很适合你:http://www.perlmonks.org/?node_id=94007

          来自链接:

          快速总结:“我的”创建一个新的 变量,'local' 临时修改 变量的值。

          ie, 'local' 暂时改变 变量的值,但仅限于 在范围内存在。

          通常使用 my,它更快,并且不会做任何奇怪的事情。

          【讨论】:

          • 虽然这可能是真的,但这基本上是一个副作用,即“local”旨在在调用堆栈中可见,而“my”则不可见。虽然覆盖全局值可能是使用“local”的主要原因,但没有理由不能使用“local”来定义新变量。
          • local 实际上并没有定义新变量。例如,当启用显式选项时,尝试使用 local 来定义变量。您需要使用“我们的”或“我的”来定义新的全局或局部变量。 “local”正确地用于给变量一个新值
          • 天哪,我真的说选项明确指的是 Perl 功能。我的意思显然是“使用严格”。我显然已经有一段时间没有用 Perl 编码了
          【解决方案7】:

          来自man perlsub

          与本地运算符创建的动态变量不同,用 my 声明的词法变量对外界完全隐藏,包括任何调用的子程序。

          因此,过于简单化了,my 使您的变量仅在声明的地方可见。 local 也使它在调用堆栈中可见。您通常希望使用my 而不是local

          【讨论】:

            【解决方案8】:

            您的困惑是可以理解的。词法作用域相当容易理解,但动态作用域是一个不寻常的概念。由于历史原因,mylocal 的名称有些不准确(或至少不直观),从而使情况变得更糟。

            my 声明了一个词法变量——从声明点到封闭块(或文件)结束都是可见的。它完全独立于程序其余部分中具有相同名称的任何其他变量。它是该块私有的。

            另一方面,local 声明对全局变量值的临时更改。更改在封闭范围的末尾结束,但变量——作为全局变量——在程序的任何地方都是可见的。

            根据经验,使用my 来声明您自己的变量,并使用local 来控制对 Perl 内置变量的更改所产生的影响。

            有关更详尽的描述,请参阅 Mark Jason Dominus 的文章 Coping with Scoping

            【讨论】:

              【解决方案9】:

              local 是一种较旧的本地化方法,从 Perl 只有动态作用域的时代开始。词法作用域对程序员来说更自然,在许多情况下也更安全。我的变量属于声明它们的范围(块、包或文件)。

              局部变量实际上属于一个全局命名空间。如果你用 local 来引用变量 $x,你实际上是在引用 $main::x,它是一个全局变量。与它的名字所暗示的相反,所有 local 所做的只是将一个新值推送到 $main::x 的值堆栈中,直到该块结束,此时旧值将被恢复。这本身就是一个有用的功能,但由于多种原因,它不是一个拥有局部变量的好方法(想想当你有线程时会发生什么!想想当你调用一个真正想要使用全局变量的例程时会发生什么?你已经本地化了!)。然而,在 Perl 5 之前的糟糕日子里,这是让变量看起来像局部变量的唯一方法。我们仍然坚持使用它。

              【讨论】:

                【解决方案10】:

                “my”变量仅在当前代码块中可见。 “本地”变量在以前可见的地方也可见。例如,如果你说“我的 $x;”并调用一个子函数,它看不到那个变量 $x。但如果你说“本地 $/;” (以清除记录分隔符的值)然后您更改从文件读取的方式在您调用的任何函数中工作。

                在实践中,您几乎总是想要“我的”,而不是“本地的”。

                【讨论】:

                  【解决方案11】:

                  查看以下代码及其输出以了解区别。

                  our $name = "Abhishek";
                  
                  sub sub1
                  {
                      print "\nName = $name\n";
                      local $name = "Abhijeet";
                  
                      &sub2;
                      &sub3;
                  }
                  
                  sub sub2
                  {
                      print "\nName = $name\n";
                  }
                  
                  sub sub3
                  {
                      my $name = "Abhinav";
                      print "\nName = $name\n";
                  }
                  
                  
                  &sub1;
                  

                  输出是:

                  Name = Abhishek
                  
                  Name = Abhijeet
                  
                  Name = Abhinav
                  

                  【讨论】:

                    【解决方案12】:

                    dinomite 使用 local 重新定义记录分隔符的示例是我在许多 perl 编程中遇到的唯一一次。我生活在一个利基 perl 环境 [安全编程] 中,但根据我的经验,它确实是一个很少使用的范围。

                    【讨论】:

                      【解决方案13】:
                      &s;
                      
                      sub s()
                      {
                          local $s="5";
                          &b;
                          print $s;
                      }
                      
                      sub b()
                      {
                          $s++;
                      }
                      

                      上面的脚本打印 6.

                      但如果我们将 local 更改为 my ,它将打印 5。

                      这就是区别。很简单。

                      【讨论】:

                        【解决方案14】:

                        我认为最容易记住它的方法就是这样。 MY 创建一个新变量。 LOCAL 临时更改现有变量的值。

                        【讨论】:

                          【解决方案15】:

                          只有在子程序中调用了子程序时才会有所不同,例如:

                          sub foo { 
                              print "$x\n"; 
                          }
                          sub bar { my $x; $x = 2; foo(); }
                              
                          bar(); 
                          

                          它不打印任何内容,因为$x 受 bar 的{} 限制,并且对调用的子例程不可见,例如:

                          sub foo { print "$x\n"; }
                          
                          sub bar { local $x; $x = 2; foo(); }
                             
                          bar(); 
                          

                          它将打印 2,因为局部变量对被调用的子例程可见。

                          【讨论】:

                            猜你喜欢
                            • 2019-05-11
                            • 2017-09-03
                            • 1970-01-01
                            • 2019-05-23
                            • 2011-01-28
                            • 2020-10-15
                            • 1970-01-01
                            • 1970-01-01
                            • 2010-12-23
                            相关资源
                            最近更新 更多