我可以复制散列而不重置其“每个"吗?迭代器? [英] Can I copy a hash without resetting its "each" iterator?

查看:23
本文介绍了我可以复制散列而不重置其“每个"吗?迭代器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 each 来遍历 Perl 哈希:

while (my ($key,$val) = 每个 %hash) {...}

然后发生了一些有趣的事情,我想打印出哈希值.起初,我考虑的是:

while (my ($key,$val) = 每个 %hash) {如果(something_interesting_happens()){foreach my $k (keys %hash) { print "$k => $hash{$k}
" }}}

但这行不通,因为每个人都知道在散列上调用keys(或values)会重置用于each,我们可能会得到一个无限循环.例如,这些脚本将永远运行:

perl -e '%a=(foo=>1);while(每个 %a){keys %a}'perl -e '%a=(foo=>1);while(每个 %a){values %a}'

没问题,我想.我可以复制一份哈希值,然后打印出来.

 if (something_interesting_happens()) {%hash2 = %hash;foreach my $k (keys %hash2) { print "$k => $hash2{$k}
" }}

但这也行不通.这也会重置 each 迭代器.事实上,在列表上下文中使用 %hash 似乎会重置它的 each 迭代器.所以这些也永远运行:

perl -e '%a=(foo=>1);而(每个 %a){%b = %a}'perl -e '%a=(foo=>1);而(每个 %a){@b = %a}'perl -e '%a=(foo=>1);而(每个 %a){打印 %a}'

这在任何地方都有记录吗?perl 可能需要使用相同的内部迭代器将散列的内容推送到返回堆栈上是有道理的,但我也可以想象不需要这样做的散列实现.

更重要的是,有什么办法可以做我想做的事吗?要在不重置 each 迭代器的情况下获取散列的所有元素?

<小时>

这也表明您也不能在 each 迭代中调试哈希.考虑在以下位置运行调试器:

%a = (foo => 123, bar => 456);而 ( ($k,$v) = 每个 %a ) {$DB::single = 1;$o .= "$k,$v;";}打印 $o;

只需检查调试器停止处的哈希值(例如,键入 p %ax %a),您就会更改程序的输出.<小时>

更新:我上传了Hash::SafeKeys 作为这个问题的一般解决方案.感谢@gpojd 为我指出正确的方向,感谢@cjm 的建议使解决方案变得更加简单.

解决方案

你试过 Storable'sdclone 复制它?它可能是这样的:

use Storable qw(dclone);我的 %hash_copy = %{ dclone( \%hash ) };

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}
" }
   }
}

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}
" }
   }

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}'

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.

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?


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;

Just by inspecting the hash where the debugger stops (say, typing p %a or x %a), you will change the output of the program.


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.

解决方案

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆