所以,我只是追踪了一个可以在这个简单的子程序中展示的错误:
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
。
答案 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>的