【问题标题】:Local variable retaining value局部变量保留值
【发布时间】:2015-07-02 18:16:34
【问题描述】:

所以,我刚刚找到了一个可以在这个简单的子程序中演示的错误:

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

【问题讨论】:

    标签: perl variables scope


    【解决方案1】:

    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时重新初始化。

    【讨论】:

      【解决方案2】:

      你所做的和这个sn-p很相似:

      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 中的一个旧错误,无法再修复,因为很多代码可能依赖于它,但如果幸运的话,您可能会看到以下警告:"Deprecated use of my() in false conditional"

      【讨论】:

        【解决方案3】:

        你发现了comma-operator

        来自 perldoc perlop:

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

        所以这实际上被认为是一个单一的语句:

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

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

        此时在子例程中,您已将1 分配给$bar。下一行是:

        push @items, $bar;
        

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

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

        【讨论】:

        • 我不确定这个答案。它不是全局变量。我正在使用严格和警告,并且在子例程之外无法访问该变量。
        • @AKHolland 抱歉,在我意识到它不是全局的但忘记修改后面的之后,我修改了第二段。
        猜你喜欢
        • 2016-06-30
        • 1970-01-01
        • 1970-01-01
        • 2023-04-07
        • 1970-01-01
        • 2021-06-10
        • 1970-01-01
        • 2013-04-29
        • 2021-09-14
        相关资源
        最近更新 更多