wiki:InsiaProgPerlLoop

Sommaire

Programmation Perl - Boucles (for, foreach, while, ...)

1. For

On retrouve la forme traditionnelle du C, qui se présente exactement de la même façon:

for (my $i = 0; $i < 10; $i++) {
  print "$i\n";
}

L'instruction attend trois éléments:

  • L'initialisation, exécutée une seul fois avant de démarrer l'itération. On peut en particulier déclarer des variables locales à la boucle;
  • Le test d'itération, qui est évalué avant chaque itération (donc avant même la première) pour savoir si elle doit être exécutée ou la boucle doit être quittée;
  • Une instruction qui est exécutée inconditionnellement à la fin de chaque itération complète

Il est possible d'omettre certaines instructions, par exemple:

my $i = 0;
for (; $i<10; ) { $i++; }
for (;;) { # boucle infinie }

On peut également contrôler l'exécution de la boucle pendant l'itération, à l'aide de 3 mots-clés:

  • last: quitte immédiatement la boucle courante
  • next: saute à la fin de l'itération et continue la boucle courante
  • redo: reprend l'itération au début comme si elle n'avait pas eu lieu (la condition n'est dons pas ré-évaluée)

Ces mot-clés s'adressent implicitement à la boucle qui contrôlent le bloc où ils sont invoqués. Exemple:

my ($x, $y);
for ($x = 0; $x < 80; $x++) {
  for ($y = 0; $y < 60; $y++) {
    last if ($x * $y < 500); # Termine la boucle for ($y...)
  }
  last if ($x * $x < 900); # Termine la boucle for ($x...)
}

Il est possible toutefois de nommer les boucles, et donc de préciser explicitement quelles boucles on veut arrêter, sauter ou redémarrer:

BOUCLE_X: for (my $x = 0; $x < 80; $x++) {
  BOUCLE_Y: for (my $y = 0; $y < 60; $y++) {
    last BOUCLE_Y if ($x * $y < 500); # Termine la boucle for ($y...)
  }
  last BOUCLE_X if ($x * $x < 900); # Termine la boucle for ($x...)
}

Cette forme ayant l'avantage de ne pas être sensible à l'imbrication de nouveaux blocs de code, et éventuellement plus lisible et plus sûre si les boucles sont longues et compliquées. C'est également le meilleur moyen de quitter plusieurs boucles imbriquées de façon simple (il existe aussi le goto, déconseillé).

2. Foreach

Pour itérer sur une liste, il existe une instruction simple, lisible et rapide:

my @courses = ("pain", "beurre", "café");
foreach my $produit (@courses) {
  print "Acheter du $produit\n";
}

Il est possible d'omettre l'itérateur (la variable qui reçoit l'élément suivant de la liste à chaque itération), dans ce cas il s'appelle implicitement $_:

foreach (@courses) {
  print "Acheter du $_\n";
}

Enfin, on a le droit d'inverser la syntaxe: on peut alors mettre une instruction (et non un bloc) en tête puis le foreach après. Ceci peut être plus lisible pour les boucles simples, et mime parfois le langage naturel:

print "Acheter du $_\n" foreach (@courses); # Notez l'absence de bloc "{}"

L'argument passé à foreach n'est autre qu'une déclaration de liste, il est donc possible d'écrire:

print "Acheter du $_\n" foreach ("pain", "beurre", "café");
for (0..9) { print "$i\n"; } # Un programmeur écrit les compteurs entiers ainsi !

On retrouve exactement les mêmes mécanismes de nommage de boucle et de contrôle avec les mots-clés last, next et redo.

Note: on peut utiliser simplement for à la place de foreach (Perl distinguant les cas d'utilisation suivant qu'une liste ou un triplet d'instructions est passé), mais pour la lisibilité on utilise toujours foreach pour itérer sur les listes.

3. While/until

On retrouve encore une construction qui vient du C, la boucle while:

my $i = 0;
while ($i < 5) {
  $i++;
}

Perl définit aussi son homonyme until où la condition est simplement inversée:

my $i = 0;
until ($i >= 5) {
  $i++;
}

On peut également utiliser les mots-clés next, last et redo. De même que pour for et foreach, on peut nommer les boucles pour être plus explicite dans leur usage. Il existe même une forme qui permet de reproduire le 3ème élément d'un for, c'est-à-dire une expression qui est toujours évaluée en fin d'itération (qu'elle ait été forcée par un next ou non:

my $i = 0;
COMPTEUR: while ($i <= 10) {
  next COMPTEUR if ($i % 2) == 0;
  print $i; # N'affiche que les nombres impairs entre 0 et 10
} continue {
  $i++;
}

Enfin, il est possible d'évaluer le test en fin d'itération, ce qui veut dire qu'on aura toujours au moins une itération qui aura lieu, avec le classique do ... while. Mais attention, il s'agit d'une construction qui ne fait pas partie du langage et a ses limitations (notamment on ne peut ni les nommer, ni utiliser les mots-clés next, last et redo):

my $i;
do {
  $i++;
} while ($i < 5);
Last modified 13 years ago Last modified on Jan 25, 2007, 11:04:49 PM