在Perl中,在循环遍历同一哈希表时,从哈希引用中删除键是否安全?为什么?

11

我基本上想要做到这一点:

foreach my $key (keys $hash_ref) {

    Do stuff with my $key and $hash_ref

    # Delete the key from the hash
    delete $hash_ref->{$key};
}

这是安全的吗?为什么?

2个回答

19

你没有遍历哈希表本身,而是在循环之前就遍历了由 keys 返回的键列表。请记住:

for my $key (keys %$hash_ref) {
   ...
}

大致相等于

my @anon = keys %$hash_ref;
for my $key (@anon) {
   ...
}

从哈希表中删除元素不会出现任何问题。


each 会对哈希表进行迭代。每次调用 each,都会返回一个不同的元素。尽管如此,删除当前元素仍然是安全的!

# Also safe
while (my ($key) = each(%$hash_ref)) {
   ...
   delete $hash_ref->{$key};
   ...
}

在遍历hash时,如果你添加或删除其中的元素,可能会跳过或重复条目--所以不要这样做。例外情况:始终可以安全地删除由each()最近返回的项。


“在当前的实现中”这个措辞有点让我担心,因为它听起来似乎有可能改变实现方式,进而导致不安全。我不会依赖它,但也不会使用 each(),而是使用 foreach 键就可以了。 - LeoNerd
@LeoNerd,旧版的Perl(至少5.10)只会说“删除始终是安全的...”出于明显的兼容性原因,我怀疑这种情况不会在不引入某些use feature或其他类似的编译指示的情况下被改变。 - Oleg V. Volkov
1
谁添加了“在当前实现中”这句话?它以前并不存在,现在也不应该存在,除非有非常好的理由。更新:似乎已经没有了。 - ysth
1
添加于 http://perl5.git.perl.org/perl.git/commit/bade7fbcf63fdefa0b4fd8a0321087860e413483,移除于 http://perl5.git.perl.org/perl.git/commit/d8021140df0281e134cb4ff987fcb69319fa11a5。 - ysth

3

这是安全的,因为keys %hash一次性提供整个列表,然后您开始迭代。然后foreach继续在此预生成的列表上工作,无论您在实际哈希表内部更改了什么。

但它会占用您的内存,因为您保留整个列表直到完成。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接