Perl中我和本地有什么区别?

时间:2008-09-24 20:12:59

标签: perl scoping

我看到他们在这个脚本中使用它们我正在尝试调试,而且文献还不清楚。有人可以为我揭开这个神秘面纱吗?

14 个答案:

答案 0 :(得分:51)

简短的回答是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语句对堆栈下面的所有内容执行的点重新定义,直到您将堆栈返回给包含{的块的调用者。 {1}}。

首先这可能令人困惑,因此请考虑以下示例。

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的全局值为1.当调用$x并运行bar时,会重新定义全局堆栈上local $x。现在,当从$x调用foo时,它会看到bar的新值2。到目前为止,这并不是很特别,因为如果没有调用$x,就会发生同样的事情。神奇的是,当local返回时,我们退出bar创建的动态范围,之前的全局local $x返回范围。因此,对于$x的最终通话,foo为1。

您几乎总是希望使用$x,因为它会为您提供您正在寻找的本地变量。一旦进入一个蓝色的月亮,my非常方便做酷事。

答案 1 :(得分:35)

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

基本上认为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

答案 2 :(得分:18)

引自Learning Perl

  

但是当地人的名字不好,或者至少是误导性地命名。我们的朋友Chip Salzenberg说,如果他有机会回到1986年的时间机器并给Larry一条建议,他会告诉Larry用“save”这个名字给当地人打电话。[14]那是因为local实际上会将给定的全局变量的值保存起来,因此稍后会自动恢复到全局变量。 (这是正确的:这些所谓的“本地”变量实际上是全局变量!)这个保存和恢复机制与我们已经在foreach循环的控制变量和@_中已经看过两次相同。子程序参数数组。

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

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

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

答案 3 :(得分:16)

我无法相信没有人与Mark Jason Dominus关于此事的详尽论述有关:

答案 4 :(得分:9)

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

  

与创建的动态变量不同   本地运算符,词汇变量   与我一起宣告是完全隐藏的   来自外部世界,包括任何   叫做子程序。如果这是真的   它是从同一个子程序调用的   本身或其他地方 - 每次通话都有   它自己的副本。

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

  

本地修改其列出的变量   成为封闭街区的“本地”,   eval,或者FILE - 以及任何   从内部调用的子程序   块。一个地方只是暂时的   全局值(意思是包)   变量。它不会创建本地   变量。这被称为动态的   作用域。词汇范围确定完成   我的,更像是C的汽车   声明。

我认为这根本不清楚,除了说“封闭区域的本地”之外,这意味着当退出块时原始值会恢复。

答案 5 :(得分:7)

谷歌真的适合你这个:http://www.perlmonks.org/?node_id=94007

从链接:

  

快速摘要:'我'创造了一个新的   变量,'本地'暂时修正   变量的值。

     

即'local'暂时更改   变量的值,但仅限   范围内。

一般使用我的,它更快,不会做任何奇怪的事情。

答案 6 :(得分:6)

来自man perlsub

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

因此,过度简化,my只会使您的变量在声明的位置可见。 local使得它在调用堆栈中也可见。您通常希望使用my代替local

答案 7 :(得分:4)

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

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

另一方面,

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

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

有关更全面的说明,请参阅Mark Jason Dominus的文章Coping with Scoping

答案 8 :(得分:3)

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

本地变量实际上属于全局命名空间。如果你用local引用变量$ x,你实际上是指$ main :: x,它是一个全局变量。与其名称所暗示的相反,所有本地操作都是将新值推送到$ main :: x的值堆栈上,直到此块结束,此时旧值将被恢复。这本身就是一个有用的功能,但是由于一系列原因而不是一个很好的方法来获取局部变量(想想当你有线程时会发生什么!并且想想当你调用一个真正想要使用全局的例程时会发生什么你已经本地化!)。然而,在Perl 5之前的旧时代,这是变换看起来像局部变量的唯一方法。我们仍然坚持使用它。

答案 9 :(得分:2)

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

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

答案 10 :(得分:2)

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

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

答案 11 :(得分:0)

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

答案 12 :(得分:0)

&s;

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

sub b()
{
    $s++;
}

以上脚本打印6。

但如果我们将本地更改为my,则会打印5。

这是不同的。简单。

答案 13 :(得分:0)

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