这里有一些关于变量以及 perl 如何处理和使用它们的知识。
当您声明$x 并赋值4 时,您实际上是在定义一个包变量。当不使用strict 编译指示(通过使用use strict 'vars' 或use strict 启用)时,您不必在变量声明前加上my 或our。因此,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() 内的$x 对routine() 是私有,并且只有routine()。
我希望语言足够清晰,可以理解!