Używam each
iterację mieszania Perl:Czy mogę skopiować hasz bez resetowania "każdego" iteratora?
while (my ($key,$val) = each %hash) {
...
}
Wtedy dzieje się coś ciekawego i chcę wydrukować hash. Początkowo uważam coś takiego:
while (my ($key,$val) = each %hash) {
if (something_interesting_happens()) {
foreach my $k (keys %hash) { print "$k => $hash{$k}\n" }
}
}
Ale to nie będzie działać, bo każdy wie, że dzwoni keys
(lub values
) na hash resetuje iterator wewnętrzne stosowane do each
i możemy uzyskać nieskończoną pętlę. Na przykład te skrypty będą działać wiecznie:
perl -e '%a=(foo=>1); while(each %a){keys %a}'
perl -e '%a=(foo=>1); while(each %a){values %a}'
Nie ma problemu, pomyślałem. Mogłem sporządzić kopię hasza i wydrukować kopię.
if (something_interesting_happens()) {
%hash2 = %hash;
foreach my $k (keys %hash2) { print "$k => $hash2{$k}\n" }
}
Ale to też nie działa. Spowoduje to również zresetowanie iteratora each
. W rzeczywistości dowolne użycie %hash
w kontekście listy wydaje się resetować jego iterator each
. Tak więc te działają na zawsze:
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}'
Czy jest to dokumentowane w dowolnym miejscu? Sensowne jest, że Perl może potrzebować użyć tego samego wewnętrznego iteratora, aby wypchnąć zawartość hasha na stos powrotny, ale mogę też wyobrazić sobie implementacje hash, które nie muszą tego robić.
Co ważniejsze, czy istnieje sposób, aby zrobić to, co chcę? Aby uzyskać dostęp do wszystkich elementów skrótu bez resetowania iteratora each
?
Sugeruje to również nie można debugować mieszania wewnątrz each
iteracji, albo. Rozważyć uruchomienie debuggera na:
%a = (foo => 123, bar => 456);
while (($k,$v) = each %a) {
$DB::single = 1;
$o .= "$k,$v;";
}
print $o;
Tylko poprzez kontrolę hash gdzie zatrzymuje debugger (powiedzmy, wpisując p %a
lub x %a
), będzie zmienić wyjście z programu.
Aktualizacja: upload Hash::SafeKeys
jako ogólne rozwiązanie tego problemu. Dzięki @gpojd za skierowanie mnie we właściwym kierunku i @cjm za sugestię, która znacznie uprościła rozwiązanie.
Wystąpił ostatnio ten sam problem. Okazało się, że Hash :: SafeKeys jest dość powolny i zależy od rozmiaru skrótu, a Hash :: StoredIterator + domyślne klawisze działają znacznie lepiej. –
@AlexandrEvstigneev - dziękuję, to jest bardzo interesujące. Wprowadzę pewne aktualizacje 'Hash :: SafeKeys' – mob