前几天,需要一次迭代一个数组的子集。最初,我用拼接做了这个 - 撕裂阵列在这种情况下没问题。它将一次返回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;
}
(实际上,我只想出了这个,但我想我还是可以发布它。看看是否还有其他人看到它。:))
(另外,如果你没有看到它,this还有另一种解释原因的方法。)
答案 0 :(得分:9)
通过将切片用作左值,每次太短时都会放大数组。因此,它永远不会缺少元素。
在前两个示例中,您仅将其用作右值,因此不会创建额外的元素。在第三个中,它是一个左值,因此创建了元素,因此可以为$_
分配。
这不是特定于切片的行为:在正常的数组访问中显示完全相同的行为。
答案 1 :(得分:6)
我认为这块代码
@array[$index..($index+$numPerTest)]
在数组中创建空元素。然后当你测试
$index < @array
你的@array刚刚变大了,你的索引永远不会超过你的@array大小。