前几天,需要一次迭代一个数组的子集.最初,我用拼接做了这个 - 撕裂阵列在这种情况下没问题.它将一次返回N个元素,或者在列表末尾留下的任何元素.一切顺利.
然后事实证明我以后需要这个数组.我转而使用数组切片,而不是拼接.繁荣!程序爆炸,到处发送堆栈溢出.什么?为什么?怎么样?我玩弄它,发现了一些可行的变体.这是演示此问题的测试脚本:
use strict; use warnings; my @array = qw(a b c d e f g h i j k l m n o p q r s t u v z x c v b a s d f g a s d f a se g); my $numPerTest = 5; my $index = 0; print "Separating out the subset before grepping it, good.\n"; while ($index < @array) { print "Iteration $index\n"; my @subset = @array[$index..($index+$numPerTest)]; @subset = grep { defined $_ } @subset; $index += $numPerTest; } $index = 0; print "Making a copy of the array before grepping works.\n"; while ($index < @array) { print "Iteration $index\n"; my @subset = grep { defined $_ } @{[ @array[$index..($index+$numPerTest)] ]}; $index += $numPerTest; } $index = 0; print "Grepping the array slice directly, explodey!\n"; while ($index < @array) { print "Iteration $index\n"; my @subset = grep { defined $_ } @array[$index..($index+$numPerTest)]; $index += $numPerTest; }
(实际上,我只想出这个,但我想我还是可以发布它.看看是否有其他人看到它.:))
(另外,如果你没有看到它,这有另一种方式来解释它为什么会发生.)
通过将切片用作左值,每次太短时都会放大数组.因此,它永远不会缺少元素.
在前两个示例中,您仅将其用作右值,因此不会创建额外的元素.在第三个中,它是一个左值,因此创建了元素,因此$_
可以分配.
这不是特定于切片的行为:在正常的数组访问中显示完全相同的行为.
我认为这块代码
@array[$index..($index+$numPerTest)]
正在数组中创建空元素.然后当你测试
$index < @array
你的@array刚刚变大了,你的索引永远不会超过你的@array大小.