使用 Dumper 将数组的哈希打印为值会导致无限递归

Tal*_*Kit 4 perl hash each

下面的代码会导致无限递归。如果不使用Dumper进行打印,则它会按预期工作。为什么Dumper会导致递归?

use Data::Dumper;

my %hash1 = (
          'key1' => ['val1']
);

while (my ($key, $value) = each %hash1) {
    print Dumper \%hash1;
}
Run Code Online (Sandbox Code Playgroud)

Sha*_*awn 6

each都怪在这里。您在循环中使用它,并Data::Dumper使用它来迭代哈希的内容。

来自文档each(强调已添加):

使用的迭代器each附加到哈希或数组,并在应用于同一哈希或数组的所有迭代操作之间共享。each因此,单个散列或数组上的所有使用都会推进相同的迭代器位置。的所有使用each还取决于对同一散列或数组的任何使用keysvalues在同一散列或数组上的任何使用,或者通过在列表上下文中引用散列(但不是数组)来重置迭代器。这使得each基于 - 的循环非常脆弱:很容易在迭代器已经部分穿过对象的情况下到达这样的循环,或者在循环体执行期间意外破坏迭代器状态。在开始循环之前显式重置迭代器很容易,但是无法将循环使用的迭代器状态与循环体期间可能执行的任何其他内容使用的迭代器状态隔离开来。为了避免这些问题,请使用foreach循环而不是while-each

就像这样:

#!/usr/bin/env perl
use warnings;
use strict;
use Data::Dumper;

my %hash1 = (
          'key1' => ['val1']
);

foreach my $key (keys %hash1) {
    print Dumper \%hash1;
}
Run Code Online (Sandbox Code Playgroud)

each基本上,除非您可以完全控制循环体中的哈希值及其结果的处理方式,否则不要使用。

这段文档解释了无限循环的确切原因:

each返回散列或数组中的所有条目后,下一次调用将each返回列表上下文和undef标量上下文中的空列表;该调用之后的下一个调用将重新开始迭代。

each代码中的循环首先Dumper()重置内部迭代器,然后重复直到返回空列表;theneach在循环测试中再次调用while,并从哈希的第一个(唯一)元素重新开始,并永远重复。