如何在 Perl 中从散列中移动块(键和值)?

How to shift block (key and value) from hash in Perl?

我有以下部分代码:

while(my $path = shift(@paths)) {
    # Do stuff
}

在循环内部有一种情况,我将另一个键添加到 @paths 因此在下一次迭代中它将处理该路径。

我不得不将 @paths 的结构从数组更改为散列。如何替换 while 循环?从这个,我试过:

while(my $path = shift(@{[keys(%paths)]}))

但问题是它将进行无限循环,因为移位适用于匿名数组而不适用于 %paths。另外我需要记住我在循环内更新 %paths 的情况:

my $p = "/some/path";
$paths{$p} = "open";

因此在循环的下一次迭代中它也将处理这条路径。我也无法使用 foreach,因为我更新了 %paths。这里最好的解决方案是什么?

检索密钥,然后delete哈希条目

while (my ($key) = keys %paths) {       # NB: list context assignment
    my $value = delete $paths{$key};
    ...
}

您可以执行与之前相同的操作,但使用不同的队列:

my @queue = keys %path;

while( my $key = shift @queue ) {
    $path{$new_key} = ...;
    push @queue, $new_key;
    }

我通常对更改正在迭代的数据结构感到紧张。 Perl 在那里可能会产生一些奇怪的效果。

另一种可能性是使用带有手动循环控制的裸块:

use strict;
use warnings;

my %hash = (
    foo => 1,
    bar => 2,
    baz => 3,
);

HASH: {
    my ($key) = keys %hash;
    my $value = delete $hash{$key};
    
    print "$key => $value\n";
    
    # Sometimes new values will be added to the hash.
    #
    if ( $key eq 'foo' ) {
        $hash{quux} = 42;
    }
    
    redo HASH if %hash;
};

我觉得裸块循环没有得到充分利用。

切换到哈希是一个错误。使用一组路径值对。

my @todo = ( [ "/some/path", "open" ] );
while (@todo) {
   my ($path, $value) = @{ shift(@todo) };

   ...

   push @todo, [ ..., ... ];

   ...
}