为什么我的数组切片上的grep导致Perl中的堆栈溢出?

时间:2009-02-19 17:37:45

标签: perl arrays

前几天,需要一次迭代一个数组的子集。最初,我用拼接做了这个 - 撕裂阵列在这种情况下没问题。它将一次返回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还有另一种解释原因的方法。)

2 个答案:

答案 0 :(得分:9)

通过将切片用作左值,每次太短时都会放大数组。因此,它永远不会缺少元素。

在前两个示例中,您仅将其用作右值,因此不会创建额外的元素。在第三个中,它是一个左值,因此创建了元素,因此可以为$_分配。

这不是特定于切片的行为:在正常的数组访问中显示完全相同的行为。

答案 1 :(得分:6)

我认为这块代码

@array[$index..($index+$numPerTest)]

在数组中创建空元素。然后当你测试

$index < @array

你的@array刚刚变大了,你的索引永远不会超过你的@array大小。