局部变量保留值

时间:2015-07-02 18:16:35

标签: perl variables scope

所以,我只是追踪了一个可以在这个简单的子程序中展示的错误:

sub foo {
    my $bar = shift or die "Missing bar", # <--- not a semicolon
    my @items = ();
    push @items, $bar;
    return @items;
}

显然,错误是子程序的第一行以逗号结尾。这有一些相当不寻常的后果,可以看出:

say foo(1); # 1
say foo(1); # 11
say foo(1); # 111
say foo(1); # 1111

现在,我知道这不是语法错误,因为逗号运算符的工作方式。我了解@items未设置为(),因为or的右侧未被触及。我的问题是,如何在子程序中用my声明的变量允许数据在子程序调用之间保持?好像my似乎以某种方式转变为our

3 个答案:

答案 0 :(得分:5)

B::Deparse在这样的练习中非常宝贵:

$ perl -MO=Deparse 31191808.pl
sub foo {
    die 'Missing bar', my(@items) = () unless my $bar = shift @_;
    push @items, $bar;
    return @items;
}

这使得它成为my $var if 0技巧/错误/好奇心的变体。它的作用是创建一个词法但静态的变量,每次调用foo时都不会重新初始化。

答案 1 :(得分:3)

您已发现comma-operator

来自perldoc perlop:

  

二进制“,”是逗号运算符。在标量上下文中,它会评估它   左参数,抛弃该值,然后评估它的权利   参数并返回该值。

所以这实际上被认为是一个单一的声明:

my $bar = shift or die "Missing bar", my @items = ();

Perl评估LHS并丢弃结果,因为这是一个并不真正丢弃任何1仍然分配给$bar的赋值,然后计算RHS并返回该值。这里一个重要的注意事项是,这意味着@items被初始化为您的sub中的静态词法变量,但在调用foo()时保持静态。与state变量的工作方式类似。

此时子程序中已将1分配给$bar。下一行是:

push @items, $bar;

Perl将$bar推送到静态词法变量@items。下一个语句返回单个元素1的列表。

foo的后续调用继续向@items数组添加元素,然后返回这些元素。这就是您从子例程调用中看到越来越多1的原因。

答案 2 :(得分:3)

您正在做的与此代码段非常相似:

use v5.14; # Implies strict
sub foo {
    my @something= () if 0;
    push @something, shift;
    say @something;
}

foo($_) for 1..5;

输出将是:

1
12
123
1234
12345

在Perl中,有条件地声明变量使得它只在该条件为真时指定一个值。如果您将if 0更改为if $_[0] == 3,则会得到完全不同的数字序列。这实际上是Perl中的一个旧错误,因为许多代码可能依赖于它而无法修复,但是如果你很幸运,你可能会看到这个警告:“在false条件中不推荐使用my()” / em>的