En Perl, la boucle foreach permet de parcourir facilement les éléments d'un tableau, où la variable de boucle par défaut ($_, ou explicitement déclarée) réfère à l'élément du tableau, au lieu de copier sa valeur.
Exemple :
my @arr = (1, 2, 3); foreach my $x (@arr) { $x *= 2; } # @arr vaut (2, 4, 6) — les éléments ont été modifiés !
Pour obtenir précisément une copie de la valeur (et non une référence à l'élément original), il faut attribuer explicitement à la variable :
foreach my $x ( @arr ) { # $x — référence à l'élément ... } # ↓↓↓↓ foreach (@arr) { my $copy = $_; ... } # $copy — copie, $_ — référence à l'élément
Il ne faut pas utiliser la même variable dans plusieurs boucles foreach imbriquées, sinon on peut obtenir des effets secondaires inattendus.
La variable dans la boucle foreach est-elle une copie indépendante, et peut-on la modifier en toute sécurité dans le corps de la boucle ?
On répond généralement : "Oui, car la boucle crée la variable elle-même — on peut la modifier comme on veut."
Réponse correcte :
En Perl, la variable de boucle par défaut (par exemple, foreach $var (@arr)) est un alias (référence) à l'élément du tableau. Toute modification de la variable de boucle entraîne une modification de l'élément original !
Pour modifier une copie temporaire — effectuez une attribution explicite à l'intérieur de la boucle :
foreach my $elem (@arr) { my $t = $elem; $t++; # seule la copie, le tableau original ne change pas }
Histoire
Histoire 1
Dans une tâche de filtrage des enregistrements, le programmeur a modifié la variable de sa boucle, sans se douter qu'il changeait les données originales. Les calculs suivants ont été effectués sur le tableau modifié, ce qui a rendu la somme des éléments incorrecte. L'erreur est apparue seulement lors de la comparaison avec un échantillon de référence.
Histoire 2
Un foreach imbriqué utilisait la même variable ($item). La variable de la boucle interne a écrasé l'état de la boucle externe, entraînant la perte des résultats du premier passage, et une partie du tableau s'est retrouvée avec des valeurs incorrectes.
Histoire 3
Un tableau de références à des hash était parcouru via foreach, et à chaque itération, une nouvelle valeur était assignée à la variable de boucle. En conséquence, les références ont été "cassées" — au lieu des valeurs référencées, il y avait maintenant des scalaires, et l'étape de traitement suivante a échoué avec une erreur de type.