在for循环范围内声明的Perl标量在迭代之间保留其值
这是我的第一个问题,很抱歉,如果这是愚蠢的,但当我最近在生产代码中遇到它时,我真的很困惑。我将问题归结为两个代码块,我希望这两个代码块做同样的事情,即为每次迭代生成一个随机数:在for循环范围内声明的Perl标量在迭代之间保留其值,perl,for-loop,Perl,For Loop,这是我的第一个问题,很抱歉,如果这是愚蠢的,但当我最近在生产代码中遇到它时,我真的很困惑。我将问题归结为两个代码块,我希望这两个代码块做同样的事情,即为每次迭代生成一个随机数: for my $num (0 .. 5) { my $id = int rand 10; print "$id\n"; } 及 第一个实现了我所期望的,但是第二个给出了相同的迭代次数$tmp在这种简化中总是未定义的,因此它只是用来显示行为,如果$tmp产生我期望的结果,则省略=$tmp 如果您能
for my $num (0 .. 5) {
my $id = int rand 10;
print "$id\n";
}
及
第一个实现了我所期望的,但是第二个给出了相同的迭代次数<代码>$tmp在这种简化中总是未定义的,因此它只是用来显示行为,如果$tmp产生我期望的结果,则省略=$tmp
如果您能深入了解为什么会发生这种情况,我将不胜感激。在my…
之后,语句修饰符的行为是未定义的(请参阅)。所以不要使用…这种奇怪行为的原因是,您已经声明了$id
,以及对它的赋值,条件是$tmp
的真实性,这使得Perl非常适合。这是怎么说的
注意:my、state或our modified with语句修饰符条件或循环构造(例如my$x if…)的行为未定义。my变量的值可能是未定义的、任何先前指定的值,或者可能是任何其他值。不要依赖它。未来版本的perl可能会做一些与您试用的perl版本不同的事情。这里有龙
如果您按如下方式更改代码,您可以自己演示这一点,这很好
for (0 .. 5) {
my $tmp;
my $id;
$id = $tmp if $tmp;
$id = int rand 10 unless $id;
print "$id\n";
}
您偶然发现了一个长期以来故意未修复的bug,因为它很有用。线路
my $id = $tmp if $tmp;
将语句修饰符(if
)应用于变量声明(my)。有条件地定义一个变量没有多大意义,但是因为my
同时具有编译时和运行时行为,这就有效地创建了一个状态变量:即一个在词汇上限定为封闭块的变量,但它在该块的执行之间保持其值
通常(有意)调用您看到的行为的形式是
my $x if 0;
自从Perl 5.10添加了
state
变量以来,这种行为就被弃用了。Perl(5.10+)的现代版本将发出警告
Deprecated use of my() in false conditional
即使在版本5.10之前,使用这种方法也有点糟糕,因为通过添加一个封闭块并在其中声明变量,可以干净地(尽管没有那么简洁)模拟状态变量。例如:
{
my $n = 0;
sub increment { return $n++; }
}
在v5.8.5、v5.10.0和v5.14.2.0上测试,谢谢。我以前从未注意到这张便条,或者至少没有考虑过它的含义。或者
my$id=$tmp$tmp:undf代码>或my$id=$tmp | | unde代码>。但是,由于您不区分不同的假值,因此可以同样轻松地使用my$id=$tmp代码>“自从Perl5.10以来,这种行为已经被弃用”是非常错误的。从那时起,警告就一直出现,但据记录,它被弃用的时间要长得多。事实上,它被记录为未定义的(现在使用非常危险),这比不推荐的(现在随时停止工作)要糟糕得多。@ikegami:虽然这种行为是官方未定义的,但它是众所周知的(如果不是广泛的话)。警告的添加和措辞含蓄地承认它是一个“特征”,尽管它肯定不是故意的。所以,虽然你在技术上是正确的,但我坚持我的措辞。Perl:向后兼容性非常好,甚至连bug都会有弃用周期-P
{
my $n = 0;
sub increment { return $n++; }
}