【问题标题】:Scope of Variable in PerlPerl 中变量的作用域
【发布时间】:2016-08-25 21:07:25
【问题描述】:

我是 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变量的值?

【问题讨论】:

  • 您希望打印出104 的值吗?

标签: perl


【解决方案1】:

这里有一些关于变量以及 perl 如何处理和使用它们的知识。

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

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

local 将在声明它的范围内存储 $x 的值,直到声明它的范围结束。所以在你的例子中,local 声明的范围是对于整个routine()(在使用local 的位置和routine() 声明的结束} 大括号之间)。离开作用域时,它会将$x 重新初始化为存储的值。这就是为什么调用routine() 后的打印语句将$x 显示为4

首先回答您的紧迫问题:

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

#! /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
}

正如在其他答案中提到的,perl 中的最佳实践是使用严格的编译指示,并在检测到错误编码时发出警告:

use strict;
use warnings 'all';

因此,运行您的代码将给出:

Global symbol "$x" requires explicit package name

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

$main::x = 4;

然后必须在代码的其余部分中将其隐式引用为$main::x

或者如果我们更喜欢访问别名,我们可以使用关键字our$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

我们尚未触及由my 关键字声明的开放词法变量(有时称为私有变量我的变量)。它们在行为上有所不同,它们仅在它们保持在范围内的时间内存在(从技术上讲,直到它们的引用计数变为 0,但这是另一个主题!)。这允许我们声明(例如)仅在您的 routine() 子例程期间创建和使用的变量:

sub routine {
    my $y = 20;

    print "y is set to $y during the duration of routine()\n";
}

my 还具有微妙的效果,允许我们在声明它们的范围内重复使用包变量名称,并为该变量使用 private 值。注意,它们的行为不像本地化变量,在范围内调用其他例程将默认使用包变量值:

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

routine() 内的$xroutine()私有,并且只有routine()

我希望语言足够清晰,可以理解!

【讨论】:

    【解决方案2】:

    “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";
    }
    

    与“my”相比,“local”最有用的属性是局部值在从局部变量范围内调用的函数中仍然可见。

    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
    

    【讨论】:

      猜你喜欢
      • 2015-04-17
      • 1970-01-01
      • 2011-07-06
      • 1970-01-01
      • 2021-10-11
      • 2011-08-06
      • 2010-12-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多