In Perl, gli hash (array associativi) sono uno strumento potente per memorizzare coppie chiave-valore. Tuttavia, lavorare con loro richiede attenzione, specialmente durante l'iterazione e la modifica della struttura. I dettagli trascurati qui portano a errori che possono essere difficili da diagnosticare.
Gli array associativi sono stati introdotti nelle prime versioni di Perl (Perl 1/2), rendendoli uno dei primi linguaggi con supporto completo per hash a livello di nucleo. Nel tempo sono emerse ulteriori funzionalità: iterazione tramite each, cancellazione (delete), trasformazione di massa (map, grep) e lotta contro le modifiche della dimensione/contenuto durante l'itrazione.
Iterare su un hash e modificare contemporaneamente il suo contenuto, in particolare eliminando elementi, può portare a effetti indesiderati: saltare elementi, rieseguire lo stesso ciclo su chiavi, o addirittura un ciclo infinito. Inoltre, l'ordine di iterazione delle chiavi non è garantito e può cambiare tra le versioni di Perl.
each, poiché il cursore interno si guasta.keys, poi passaci sopra in un ciclo separato ed elimina.while (my ($k, $v) = each %h) per l'iterazione normale, ma non combinarlo con delete all'interno del ciclo se non vuoi sorprese.Esempio di cancellazione corretta degli elementi:
my %h = (a=>1, b=>2, c=>3); for my $k (keys %h) { delete $h{$k} if $h{$k} == 2; }
Esempio di approccio errato:
while (my ($k, $v) = each %h) { delete $h{$k}; # Questo può portare a saltare chiavi }
Caratteristiche chiave:
È possibile eliminare in sicurezza elementi dall'hash all'interno del ciclo while (each %h)?
No, questo può portare a saltare parti dell'hash a causa del ripristino del cursore di iterazione interno.
Cosa succede all'ordine delle chiavi dopo l'eliminazione degli elementi dall'hash?
L'ordine non è garantito e può cambiare. Inoltre, l'ordine di iterazione tra programmi in Perl identici può differire.
È possibile modificare il valore di un elemento dell'hash durante l'iterazione tramite each?
Sì, modificare il valore (ma non la struttura) è sicuro.
Esempio:
while (my ($k, $v) = each %h) { $h{$k} = $v + 10; }
Utilizzare l'eliminazione di elementi tramite each in un unico ciclo:
my %h = (a=>1, b=>2, c=>3); while (my ($k, $v) = each %h) { delete $h{$k} if $v == 1; }
Pro:
Contro:
Creazione di un elenco di chiavi per la cancellazione:
my %h = (a=>1, b=>2, c=>3); for my $k (keys %h) { delete $h{$k} if $h{$k} == 1; }
Pro:
Contro: