4

之前看过《Effective Perl Programming》这本书的相关内容,但并没有真正看懂。今天遇到了一个问题,代码如下。

my $vname = "a";
my @a = qw(1 2 3);
local @array = @$vname; 
foreach(@array) { print "$_\n"; };

它什么也不输出。然后我修改了这一行:

local @a = qw(1 2 3);  

只需将“my”替换为“local”,即可使用。所以我想弄清楚它们之间有什么区别。

4

5 回答 5

14

有一个perldoc条目可以回答这个问题perlfaq7

动态和词法(静态)作用域有什么区别?之间local()my()

local($x)保存全局变量的旧值$x并在子例程的持续时间内分配一个新值,该值在从该子例程调用的其他函数中可见。这是在运行时完成的,因此称为动态范围。local()总是影响全局变量,也称为包变量或动态变量。 my($x)创建一个仅在当前子例程中可见的新变量。这是在编译时完成的,因此称为词法或静态作用域。my()总是影响私有变量,也称为词法变量或(不正确的)静态(ly 作用域)变量。

例如:

sub visible {
    print "var has value $var\n";
}

sub dynamic {
    local $var = 'local';   # new temporary value for the still-global
    visible();              #   variable called $var
}

sub lexical {
    my $var = 'private';    # new private variable, $var
    visible();              # (invisible outside of sub scope)
}

$var = 'global';
visible();              # prints global
dynamic();              # prints local
lexical();              # prints global

请注意,值“private”是如何被打印出来的。那是因为$var只有在函数块中具有该值lexical() ,并且它对被调用的子例程隐藏。

总之,local()不会使您认为的私有局部变量。它给全局变量一个临时值。如果您想要私有变量,my() 就是您要查找的内容。

请参阅Private Variables via my()perlsubTemporary Values via local()perlsub 中的详细信息。

于 2012-08-30T06:00:32.463 回答
9

my创建一个新变量。它只能在声明它的词法范围内看到。

local创建在范围退出时恢复的全局变量的临时备份,但不会缩小其范围(仍然可以在全局范围内看到)。它不会创建新变量。

您总是希望尽可能使用my,但是local当您必须处理全局变量(例如$_)时,这是一个不错的近似值。

于 2012-08-30T04:49:48.353 回答
8

Perl 中有两种变量作用域:

  • 全局变量:它们驻留在当前包中,可以从外部访问并且可以具有“本地”值。该名称可以用作“stash”、包变量哈希/符号表中的键。
  • 词法变量:它们驻留在当前范围内(大致由大括号分隔)。没有可以检查的符号表。

词法变量和全局变量互不干扰,可以有两个不同的变量同名。

大多数 Perl 变量魔法都发生在全局变量中。以下语法适用于全局变量:

our $var;
$::var;
$main::var;
${'var'};
local $var;

但不是my $var

所以我们可以写:

@::array = qw(a b c);
my @secondArray = @{array};

复制数组。我们还可以使用存储在变量中的名称查找数组:

@::array = qw(a b c);
my $name = "array";
my @secondArray = @{$name};

最后一行缩写为… = @$name.

这对于词法变量是不可能的,因为它们不驻留在存储中。

local函数将“本地”值分配给当前范围内的全局变量(仅限全局变量)以及从该范围内调用的所有子范围(“动态范围”)。

最初(在 Perl 4 中)干预变量名和存储是模拟引用的唯一方法。这些用法现在大多已经过时了约 2 年,因为有可用的参考资料(更安全的方法)。

于 2012-08-30T04:35:05.023 回答
2

我想关注您使用它们的主要情况:

  • 对于您希望将其限制在特定块中的变量,我应该是您的“默认值”。这应该是大部分时间
  • 如果您希望使用全局变量,尤其是特殊变量之一,则local很有用。例如

    local $/;                          # enable "slurp" mode
    local $_ = <$some_file_handle>;    # whole file now here
    

    使用 local 可以防止您的更改影响其他代码(包括您未编写的模块)

于 2012-08-30T06:51:40.093 回答
0

在您的情况下,不同之处在于local解决了符号表中的变量而my没有解决。这很重要,因为如何使用它:

local @array = @$vname;

也就是说,您将$vname其用作符号参考(一种有问题的做法,没有no strict 'refs'告诉我们您知道自己在做什么)。配额:

只有包变量(全局变量,即使已本地化)对符号引用可见。词法变量(用 my() 声明)不在符号表中,因此对这种机制是不可见的。

所以符号引用只能引用符号表中的变量。无论您声明@a为词法的 withmy还是全局的 with local@$vname都只引用@main::a. 当你说

local @a = qw(1 2 3);

, 你给@main::a. 当你说

my @a = qw(1 2 3);

,您正在创建一个新的词法变量@a并为其赋值,但@main::a未定义。什么时候

local @array = @$vname;

然后访问 的值@main::a,如果发现它是未定义的并设置它的值@array

如果这一切看起来令人困惑,那是因为它是。这就是为什么强烈鼓励你使用strictand warnings(这在这段代码中会很爆炸)并且不鼓励使用符号引用,除非你真的知道你在做什么。

于 2012-08-30T18:24:06.240 回答