W Perl istnieje kilka sposobów obejścia hashy: przez each, przez listę kluczy (keys) i foreach, a także przez values. Od początku języka zakładano, że hashy będą używane do szybkiego dostępu do danych, dlatego metody przechodzenia stworzono z myślą o wydajności i minimalizacji przydzielania dodatkowej pamięci.
Problem: Przy używaniu tych technik pojawia się wiele pułapek: zmiana hasha w trakcie iteracji, zapamiętywanie iteratora, porządek elementów, uboczny wpływ each na hash, a także ryzyko nieprzewidywalnego zachowania podczas zagnieżdżonej iteracji.
Rozwiązanie: Dla bezpiecznej i przewidywalnej iteracji zaleca się używanie foreach my $key (sort keys %hash), nie modyfikowanie hasha w trakcie iteracji, a dla each — zawsze resetowanie iteratora za pomocą keys %hash przed nową pętlą.
Przykład kodu:
my %hash = ( a => 1, b => 2, c => 3 ); foreach my $key (sort keys %hash) { print "$key: $hash{$key} "; # Przewidywalna kolejność }
Kluczowe cechy:
keys zwraca kopię listy kluczy, porządek nie jest określony.each jest zapamiętany przez hash, kilka pętli jednocześnie możliwe jest tylko z różnymi hashami.each używa się pustego wywołania keys.Czy można bezpiecznie modyfikować hash podczas iteracji przez each?
Nie, prowadzi to do niekontrolowanych konsekwencji: dane mogą być pominięte lub zliczone wielokrotnie.
Czy jeśli wywołać each dla dwóch różnych hashów, będzie wspólny iterator?
Nie, iteratory są niezależne dla każdego hasha.
Czy można zagnieżdżać dwa cykle przez each dla tego samego hasha?
Nie, iterator będzie "zrywał się" i wyniki będą nieprzewidywalne. Dla takich przypadków użyj keys i zagnieżdżonych pętli.
Użycie each do przechodzenia po hashu w funkcji, która jest wywoływana wielokrotnie z różnymi częściami tego samego hasha. Iterator się zrywa, część danych jest tracona.
Zalety:
Wady:
Użycie foreach i keys do przechodzenia, pełna iteracja z wyraźnym zachowaniem kluczy w osobnej tablicy.
Zalety:
Wady: