Sto usando each
per scorrere un hash Perl:Posso copiare un hash senza resettare il suo "ogni" iteratore?
while (my ($key,$val) = each %hash) {
...
}
Poi succede qualcosa di interessante e voglio stampare il hash. In un primo momento mi considero qualcosa di simile:
while (my ($key,$val) = each %hash) {
if (something_interesting_happens()) {
foreach my $k (keys %hash) { print "$k => $hash{$k}\n" }
}
}
Ma questo non funzionerà, perché tutti sanno che la chiamata keys
(o values
) su un hash reimposta l'iteratore interno utilizzato per each
, e possiamo ottenere un ciclo infinito. Ad esempio, questi script verranno eseguiti per sempre:
perl -e '%a=(foo=>1); while(each %a){keys %a}'
perl -e '%a=(foo=>1); while(each %a){values %a}'
Nessun problema, ho pensato. Potrei fare una copia dell'hash e stampare la copia.
if (something_interesting_happens()) {
%hash2 = %hash;
foreach my $k (keys %hash2) { print "$k => $hash2{$k}\n" }
}
Ma anche questo non funziona. Ciò ripristina anche l'iteratore each
. In effetti, qualsiasi utilizzo di %hash
in un contesto di elenco sembra reimpostare il suo iteratore each
. Quindi anche questi durano all'infinito:
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}'
È documentato ovunque? Ha senso che perl potrebbe aver bisogno di usare lo stesso iteratore interno per spingere i contenuti di un hash su uno stack di restituzione, ma posso anche immaginare implementazioni di hash che non hanno bisogno di farlo.
Ancora più importante, c'è un modo per fare ciò che voglio? Per ottenere tutti gli elementi di un hash senza reimpostare l'iteratore each
?
Questo suggerisce, inoltre, non è possibile eseguire il debug di un hash all'interno di un each
iterazione, neanche. Si consideri che esegue il debugger on:
%a = (foo => 123, bar => 456);
while (($k,$v) = each %a) {
$DB::single = 1;
$o .= "$k,$v;";
}
print $o;
Proprio controllando l'hash in cui il debugger si interrompe (ad esempio, digitando p %a
o x %a
), si cambierà l'output del programma.
Aggiornamento: ho caricato Hash::SafeKeys
come una soluzione generale a questo problema. Grazie a @gpojd per avermi indicato nella giusta direzione e @cjm per un suggerimento che ha reso la soluzione molto più semplice.
Recentemente si è verificato lo stesso problema. Ho scoperto che Hash :: SafeKeys è piuttosto lento e dipende dalle dimensioni dell'hash e le chiavi predefinite di Hash :: StoredIterator + funzionano molto meglio. –
@AlexandrEvstigneev - grazie, questo è molto interessante. Aggiungerò alcuni aggiornamenti a 'Hash :: SafeKeys' – mob