【发布时间】:2012-06-10 21:10:35
【问题描述】:
我正在使用each 来遍历 Perl 哈希:
while (my ($key,$val) = each %hash) {
...
}
然后发生了一些有趣的事情,我想打印出哈希。一开始我会考虑这样的事情:
while (my ($key,$val) = each %hash) {
if (something_interesting_happens()) {
foreach my $k (keys %hash) { print "$k => $hash{$k}\n" }
}
}
但这行不通,因为每个人都知道在哈希上调用keys(或values)会重置用于each 的内部迭代器,并且我们可能会陷入无限循环。例如,这些脚本将永远运行:
perl -e '%a=(foo=>1); while(each %a){keys %a}'
perl -e '%a=(foo=>1); while(each %a){values %a}'
没问题,我想。我可以复制哈希,然后打印出来。
if (something_interesting_happens()) {
%hash2 = %hash;
foreach my $k (keys %hash2) { print "$k => $hash2{$k}\n" }
}
但这也行不通。这也会重置 each 迭代器。事实上,在列表上下文中对%hash 的任何使用似乎都会重置其each 迭代器。所以这些也永远运行:
perl -e '%a=(foo=>1); while(each %a){%b = %a}'
perl -e '%a=(foo=>1); while(each %a){@b = %a}'
perl -e '%a=(foo=>1); while(each %a){print %a}'
这在任何地方都有记录吗? perl 可能需要使用相同的内部迭代器将哈希的内容推送到返回堆栈是有道理的,但我也可以想象不需要这样做的哈希实现。
更重要的是,有什么方法可以做我想做的事吗?要在不重置 each 迭代器的情况下获取哈希的所有元素?
这也表明您也不能在 each 迭代中调试哈希。考虑在以下位置运行调试器:
%a = (foo => 123, bar => 456);
while ( ($k,$v) = each %a ) {
$DB::single = 1;
$o .= "$k,$v;";
}
print $o;
只需检查调试器停止的哈希值(例如,输入p %a 或x %a),您将更改程序的输出。
更新:我上传了Hash::SafeKeys 作为此问题的通用解决方案。感谢@gpojd 为我指明了正确的方向,感谢@cjm 的建议,使解决方案变得更加简单。
【问题讨论】:
-
最近遇到了同样的问题。发现 Hash::SafeKeys 非常慢并且取决于哈希大小,而 Hash::StoredIterator + 默认键的性能要好得多。
-
@AlexandrEvstigneev - 谢谢,这很有趣。我会更新
Hash::SafeKeys
标签: perl