在 Perl 中,my 和 local 有什么区别?

我看到他们两个使用在这个脚本中,我正在尝试调试和文献只是不清楚。有人能帮我解开这个谜团吗?

45842 次浏览

好吧,谷歌确实在这一点上为你工作: http://www.perlmonks.org/?node_id=94007

链接如下:

快速总结: “ my”创建一个新的 变量,“本地”临时修正 变量的值。

即“ local”< em > 暂时更改 变量 的值,但仅限于 在范围 内,它存在于。

通常使用我的,它的速度更快,不会做任何怪异的事情。

来自 man perlsub:

与局部运算符创建的动态变量不同,使用 my 声明的词法变量完全隐藏于外部世界,包括任何所谓的子例程。

因此,简单地说,my使您的变量只在声明它的地方可见。local也使它在调用堆栈中可见。您通常需要使用 my而不是 local

“ my”变量仅在当前代码块中可见。“局部”变量在以前可见的地方也是可见的。例如,如果您说“ my $x;”并调用一个子函数,它就不能看到变量 $x。但是,如果您说“ local $/;”(为了取消记录分隔符的值) ,那么您就改变了从文件中读取的方式,这种方式在您调用的任何函数中都有效。

实际上,你几乎总是想要“我的”,而不是“本地”。

Http://perldoc.perl.org/perlsub.html#private-variables-via-my

创建的动态变量不同 局部运算符,词法变量 声明与我完全隐藏 来自外面的世界,包括任何 子程序。如果 是同一个子程序调用的 不管是自己还是别人,每个电话都能接到 它自己的复制品。

Http://perldoc.perl.org/perlsub.html#temporary-values-via-local

局部变量修改其列出的变量 是“本地”的封闭块, Eval,或者执行 FILE-和任意 调用的子程序 当地人只是暂时的 值到全局(意义包) 变量。它不创建局部 这就是所谓的动态 范围,词汇范围已经完成了 天哪,更像是 C 的自动档 声明。

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

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

基本上可以将 my看作是创建一个变量并将其锚定到{}(又名作用域)的一个块。

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在词法作用域中将变量标记为 private,而 local在动态作用域中将变量标记为 private。

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

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

但是这只是 Perl 在做你想做的事情,通常你会有这样的东西:

sub Foo {
my $x = shift;


print "$x\n";
}

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

要理解 local,您需要考虑程序运行时的调用堆栈。当一个变量是 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确实可以用来做一些很酷的事情。

引自 < em > Learning Perl :

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

因此,local保存全局变量的当前值,然后将其设置为某种形式的空值。你会经常看到它用来吸收整个文件,而不是仅仅引导一行:

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

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

你的困惑是可以理解的。词汇范围确定相当容易理解,但动态范围确定是一个不寻常的概念。由于历史原因,mylocal的名字有些不准确(或者至少不直观) ,这使情况变得更糟。

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

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

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

更详细的描述见 Mark Jason Dominus 的文章 应对范围界定

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

局部变量实际上属于全局名称空间。如果使用 local 引用变量 $x,实际上就是引用 $main: : x,它是一个全局变量。与它的名称所暗示的相反,所有的本地操作都是将一个新值推送到 $main: : x 的值堆栈上,直到这个块结束,这时旧值将被恢复。这本身是一个非常有用的特性,但是由于很多原因,这并不是一个拥有本地变量的好方法(想想当你拥有线程时会发生什么吧!)!然后想想当你调用一个真正想要使用你已经局部化的全局的例程时会发生什么!).然而,在 Perl 5之前糟糕的旧时代,这是使变量看起来像局部变量的唯一方法。我们还是无法摆脱它。

我不敢相信没有人把马克 · 杰森 · 多米纳斯关于这个问题的详尽论述联系起来:

  • 应对范围界定

  • 之后,如果你想知道 local到底有什么好处,那么 local的七种有用用途

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

&s;


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


sub b()
{
$s++;
}

上面的脚本打印6。

但是,如果我们改变本地为我,它将打印5。

这就是区别,很简单。

查看下面的代码及其输出,以了解其中的差异。

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

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

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

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,因为局部变量对于被调用的子例程是可见的。

#!/usr/bin/perl


sub foo { print ", x is $x\n"; }


sub testdefault { $x++; foo(); }        # prints 2


sub testmy { my $x; $x++; foo(); }       # prints 1


sub testlocal { local $x = 2; foo(); }    # prints 2. new set mandatory




print "Default, everything is global";
$x = 1;
testdefault();


print "My does not affect function calls outside";
$x = 1;
testmy();


print "local is everything after this but initializes a new";
$x = 1;
testlocal();

正如 testlocal 注释中提到的,声明“ local $x;”意味着 $x 现在是 undef