我可以复制散列而不重置其“每个"散列吗?迭代器? [英] Can I copy a hash without resetting its "each" iterator?
问题描述
我正在使用each
遍历Perl哈希:
I am using each
to iterate through a Perl hash:
while (my ($key,$val) = each %hash) {
...
}
然后发生了一些有趣的事情,我想打印出哈希值.起初,我考虑类似的东西:
Then something interesting happens and I want to print out the hash. At first I consider something like:
while (my ($key,$val) = each %hash) {
if (something_interesting_happens()) {
foreach my $k (keys %hash) { print "$k => $hash{$k}\n" }
}
}
但是那是行不通的,因为每个人都知道在哈希上调用keys
(或values
)会重置用于each
的内部迭代器,我们可能会遇到无限循环.例如,这些脚本将永远运行:
But that won't work, because everyone knows that calling keys
(or values
) on a hash resets the internal iterator used for each
, and we may get an infinite loop. For example, these scripts will run forever:
perl -e '%a=(foo=>1); while(each %a){keys %a}'
perl -e '%a=(foo=>1); while(each %a){values %a}'
没问题,我想.我可以复制哈希,然后打印出来.
No problem, I thought. I could make a copy of the hash, and print out the copy.
if (something_interesting_happens()) {
%hash2 = %hash;
foreach my $k (keys %hash2) { print "$k => $hash2{$k}\n" }
}
但这也不起作用.这也会重置each
迭代器.实际上,在列表上下文中使用%hash
似乎都会重置其each
迭代器.因此,它们也将永远运行:
But that doesn't work, either. This also resets the each
iterator. In fact, any use of %hash
in a list context seems to reset its each
iterator. So these run forever, too:
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可能需要使用相同的内部迭代器来将哈希的内容压入返回堆栈,这是有道理的,但是我也可以想象不需要这样做的哈希实现.
Is this documented anywhere? It makes sense that perl might need to use the same internal iterator to push a hash's contents onto a return stack, but I can also imagine hash implementations that didn't need to do that.
更重要的是,有什么方法可以做我想要的吗?要获得哈希的所有元素而无需重置each
迭代器?
More importantly, is there any way to do what I want? To get to all the elements of a hash without resetting the each
iterator?
这也建议您也不能在each
迭代中调试哈希.考虑在以下位置运行调试器:
This also suggests you can't debug a hash inside an each
iteration, either. Consider running the debugger on:
%a = (foo => 123, bar => 456);
while ( ($k,$v) = each %a ) {
$DB::single = 1;
$o .= "$k,$v;";
}
print $o;
只需检查调试器停止处的哈希(例如,键入p %a
或x %a
),就可以更改程序的输出.
Just by inspecting the hash where the debugger stops (say, typing p %a
or x %a
), you will change the output of the program.
更新:我上传了 Hash::SafeKeys
作为这个问题的一般解决方案.感谢@gpojd为我指出正确的方向,并感谢@cjm的建议使解决方案更加简单.
Update: I uploaded Hash::SafeKeys
as a general solution to this problem. Thanks @gpojd for pointing me in the right direction and @cjm for a suggestion that made the solution much simpler.
推荐答案
您是否尝试过可存储的 dclone
要复制吗?可能是这样的:
Have you tried Storable's dclone
to copy it? It would probably be something like this:
use Storable qw(dclone);
my %hash_copy = %{ dclone( \%hash ) };
这篇关于我可以复制散列而不重置其“每个"散列吗?迭代器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!