Perl中的变量范围

时间:2016-08-25 10:28:05

标签: perl

我是Perl的新手,我对子例程中变量的使用产生了疑问。

    #! /usr/bin/perl

    $x=4;
    &routine;
    print "value of x in main is $x\n";

    sub routine
    {
      local $x = 10;
      print "value of x in routine is $x\n";
      print "value of x in main is $x\n";       #what should be replaced in $x to get correct answer
    }

在程序中,应该在这一行中替换什么

    print "value of x in main is $x\n";

在main函数中获取$ x变量的值?

2 个答案:

答案 0 :(得分:1)

“local”语句有效地隐藏了全局变量的原始值。如果您需要原始值,则必须在“本地”声明之前复制一份:

$x=4;
&routine;
print "value of x in main is $x\n";

sub routine
{
    my $originalX = $x;
    local $x = 10;
    print "value of x in routine is $x\n";
    print "value of x in main is $originalX\n";
}

“本地”与“我的”相对的最有用的属性是本地值在局部变量范围内调用的函数中仍然可见。

our $x=4;
foo();
print "value of x in main is $x\n";

sub foo {
  local $x = 10;
  print "value of x in foo is $x\n";
  bar();
}

sub bar {
  print "value of x in bar is $x\n";
}

结果

value of x in foo is 10
value of x in bar is 10
value of x in main is 4

答案 1 :(得分:1)

关于变量以及perl如何处理和使用它们,这里有一些事情要理解。

当您声明$x并指定值4时,您实际上是在定义一个包变量。如果不使用strict pragma(通过使用use strict 'vars'use strict启用),则不必将变量声明置于myour之前。因此,Perl将默认将$x初始化为包变量。包通过package关键字设置,如果省略,则perl默认为main包。这意味着您已创建名为$main::x的包变量,其值为4。在保留在main包中的同时,您可以使用别名 $x来表示$main::x

可以在主包范围内的任何位置使用包变量(通常称为全局变量),这就是您可以在子例程{{1}中访问$x的原因}。

routine()将在声明范围的持续时间内存储local的值,直到声明它的范围结束。所以在您的示例中,$x的范围{1}}声明适用于整个local(使用routine()之间和local声明的结束}括号)。离开范围时,它会将routine()重新初始化为存储的值。这就是调用$x后的print语句将routine()显示为$x的原因。

首先回答您的问题:

由于4特定于其所使用的闭包,因此您可以在local中创建单独的闭包。这样,您可以在该范围内本地化routine(),但在子例程中保留$x的包变量:

$x

正如其他答案所述,perl的最佳实践是使用严格的编译指示以及在检测到错误编码时要求警告:

#! /usr/bin/perl 

$x=4;  # declare a package variable $main::x
routine();
print "value of x in main is $x\n";

sub routine {
    # now create a closure, so we can localize the package variable
    # within its own scope
    {
        local $x = 10;
        print "value of x routine, within locally scoped closure is $x\n";
    }
    print "value of x _from_ main is $x\n";  #will now print 4
}

因此,运行代码将提供:

use strict; use warnings 'all';

我们可以通过几种方式解决这个问题,我们可以使用包名称声明它:

Global symbol "$x" requires explicit package name

然后必须在代码的其余部分中将其隐含地引用为$main::x = 4;

或者如果我们希望有权访问别名,我们可以使用关键字$main::xour声明为包变量,然后在其余部分将其称为$main::x我们的代码。

$x

如果涵盖了这些要点,您可以获得最终推荐的解决方案:

our $x=4;      # (is the same as writing $main::x = 4, but you also
               # can refer to it by its alias $x from this point onwards).

额外信息

请注意,即使在该范围内调用其他子例程,本地化变量仍保留在范围内:

#! /usr/bin/perl 

use strict;
use warnings 'all';

our $x=4;  # declare a package variable $main::x
routine();
print "value of x in main is $x\n";

sub routine {
    # now create a closure, so we can localize the package variable
    # within its own scope
    {
        local $x = 10;
        print "value of x routine, within locally scoped closure is $x\n";
    }
    print "value of x _from_ main is $x\n";  # will now print 4
}

将输出:

our $x=4;
routine();

sub routine {
    {
        local $x = 10;
        print "routine() localized, x is $x\n";
        another_routine();
    }
    print "routine() x is $x\n";
}

sub another_routine {
    print "another_routine() still localized, x is $x\n";
}

我们没有触及routine() localized, x is 10 another_routine() still localized, x is 10 routine() x is 4 关键字声明的开放词汇变量(有时称为私有变量我的变量 )。它们的行为不同,它们只在它们保持在范围内的时间内存在(技术上很好,直到它们的引用计数变为0,但这是另一个主题!)。这允许我们声明仅在my子例程中创建和使用的变量(例如):

routine()

sub routine { my $y = 20; print "y is set to $y during the duration of routine()\n"; } 还具有允许我们重用包变量名称的微妙效果,并在声明范围的持续时间内对该变量使用私有值。注意,它们的行为不像本地化变量,并且在作用域内调用其他例程将默认使用包变量值:

my

将输出:

our $x=4;
routine();

sub routine {
    my $x = 20;

    print "routine() x is $x\n";
    another_routine();
}

sub another_routine {
    print "another_routine() x is $x\n";
}
routine() x is 20 another_routine() x is 4 内的$x 私有routine()且仅routine()

我希望语言能够清晰明白!