我和Perl中的local和有什么不一样?

时间:2020-03-06 14:41:12  来源:igfitidea点击:

我正在尝试调试的脚本中都使用了它们,文献还不清楚。有人可以为我揭开神秘面纱吗?

解决方案

那么Google确实可以在这一方面为我们工作:http://www.perlmonks.org/?node_id=94007

从链接:

Quick summary: 'my' creates a new
  variable, 'local' temporarily amends
  the value of a variable.
  
  ie, 'local' temporarily changes the
  value of the variable, but only
  within the scope it exists in.

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

来自man perlsub

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

因此,过分简化,my使变量仅在声明的位置可见。 local也使它在调用堆栈中可见。我们通常会希望使用"我"而不是"本地"。

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

Unlike dynamic variables created by
  the local operator, lexical variables
  declared with my are totally hidden
  from the outside world, including any
  called subroutines. This is true if
  it's the same subroutine called from
  itself or elsewhere--every call gets
  its own copy.

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

A local modifies its listed variables
  to be "local" to the enclosing block,
  eval, or do FILE --and to any
  subroutine called from within that
  block. A local just gives temporary
  values to global (meaning package)
  variables. It does not create a local
  variable. This is known as dynamic
  scoping. Lexical scoping is done with
  my, which works more like C's auto
  declarations.

我不认为这是完全不清楚的,除了说"对于封闭的块是本地的"以外,这意味着当块退出时将恢复原始值。

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

基本上将" 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

简短的答案是," 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确实很容易做一些很酷的事情。

从学习Perl引用:

But local is misnamed, or at least misleadingly named. Our friend Chip Salzenberg says that if he ever gets a chance to go back in a time machine to 1986 and give Larry one piece of advice, he'd tell Larry to call local by the name "save" instead.[14] That's because local actually will save the given global variable's value away, so it will later automatically be restored to the global variable. (That's right: these so-called "local" variables are actually globals!) This save-and-restore mechanism is the same one we've already seen twice now, in the control variable of a foreach loop, and in the @_ array of subroutine parameters.

因此,local保存全局变量的当前值,然后将其设置为某种形式的空值。我们会经常看到它曾经用于整个文件,而不是仅一行开头:

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

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

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

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

另一方面,local声明对全局变量的值的临时更改。更改在封闭范围的结尾处结束,但是变量-being global-在程序中的任何位置都可见。

根据经验,使用" my"声明我们自己的变量,使用" local"来控制更改对Perl内置变量的影响。

有关更全面的描述,请参见Mark Jason Dominus的文章"应对范围确定"。

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

实际上,局部变量实际上属于全局名称空间。如果使用局部变量引用$ x,则实际上是全局变量$ main :: x。与其名称所暗示的相反,所有本地操作都是将新值压入$ main :: x的值堆栈中,直到该块的末尾为止,届时将恢复旧值。这本身就是一个有用的功能,但是由于多种原因,拥有局部变量也不是一个好方法(想一想当我们拥有线程时会发生什么!并想想当我们调用一个真正想使用全局变量的例程时会发生什么)我们已经本地化了!)。但是,这是让变量在Perl 5之前的糟糕年代里看起来像局部变量的唯一方法。我们仍然坚持使用它。

我无法相信没有人与马克·杰森·多米纳斯(Mark Jason Dominus)有关此事的详尽论文有关:

  • 应对范围
  • 然后,如果我们想知道local到底有什么用,那么local的七种有用用法

dinomite使用local重新定义记录定界符的示例是我在许多Perl编程中唯一遇到的例子。我生活在一个利基的Perl环境中(安全编程),但是根据我的经验,这确实是一个很少使用的范围。

&s;

sub s()
{
    local $s="5";
    &b;
    print $s;
}

sub b()
{
    $s++;
}

上面的脚本打印6.

但是,如果我们将本地更改为my,它将打印5.

这是区别。简单的。