Rust Basics Series #7 : Utiliser des boucles dans Rust
Les boucles sont une autre façon de gérer le flux de contrôle de vos programmes. Découvrez les boucles for, while et 'loop' dans Rust.
Dans l'article précédent de la série Rust, j'ai passé en revue l'utilisation des mots-clés if et else pour gérer le flux de contrôle de votre programme Rust.
C'est une façon de gérer le flux de contrôle de votre programme. L’autre façon de procéder consiste à utiliser des boucles. Examinons donc les boucles dans cet article de suivi.
Boucles disponibles dans Rust
Le langage de programmation Rust comporte trois boucles différentes en fonction de ce que vous souhaitez réaliser et de ce qui est disponible :
pour
-
alors que
boucle
Je suppose que vous connaissez for
et while
mais loop
pourrait être nouveau ici. Commençons par des concepts familiers.
La boucle for
La boucle for
est principalement utilisée pour parcourir quelque chose appelé itérateur.
Cet itérateur peut être créé à partir de n'importe quoi, d'un tableau, d'un vecteur (ce sera bientôt abordé !), d'une plage de valeurs ou de tout ce qui est personnalisé. Le ciel est la limite ici.
Regardons la syntaxe de la boucle for
.
for iterating_variable in iterator {
<statement(s)>;
}
La iterating_variable
est plus généralement connue sous le nom de i
dans la plupart des didacticiels sur les autres langages de programmation ;)
Et un itérateur
, comme je l'ai dit, peut être vraiment tout ce qui indique quelle est la valeur suivante, le cas échéant.
Comprenons cela à l'aide d'un programme.
fn main() {
let my_arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
println!("iteration over an array");
for element in my_arr {
println!("{}", element);
}
println!("\niteration over a real iterator");
for element in my_arr.iter() {
println!("{}", element);
}
println!("\nPython-style range");
for element in 0..10 {
println!("{}", element);
}
}
Ici, j'ai déclaré un tableau contenant 10 nombres, de 0 à 9. Sur la boucle for
qui se trouve à la ligne 5, je spécifie simplement ce tableau comme itérateur et Rust gère automatiquement l'itération sur tous les nombres. éléments de ce tableau pour moi. Aucune magie my_arr[i]
sophistiquée n'est nécessaire.
Mais à la ligne 10, j'appelle la fonction .iter()
sur le tableau. Il s'agit d'une mention explicite de l'obtention d'un itérateur basé sur les valeurs qui composent my_arr
. La seule différence entre cette boucle et la boucle de la ligne 5 est qu'ici vous êtes explicite en appelant la fonction .iter()
sur le tableau.
Appeler la fonction .iter()
sur un type de données, dans ce contexte, n'est pas strictement nécessaire. Puisqu'il s'agit d'un tableau, qui est un type de données fourni par le langage lui-même, Rust sait déjà comment le gérer. Mais vous en aurez besoin avec des types de données personnalisés.
Enfin, à la ligne 15, nous avons une boucle for qui boucle sur une plage. En quelque sorte. Si vous regardez attentivement, cette plage ressemblera beaucoup au "type" Slice. Rust le sait aussi et gère les itérations pour vous (haha, vous comprenez ?).
Le résultat ressemble à ceci :
iteration over an array
0
1
2
3
4
5
6
7
8
9
iteration over a real iterator
0
1
2
3
4
5
6
7
8
9
Python-style range
0
1
2
3
4
5
6
7
8
9
La boucle while
La boucle while
peut être considérée comme très similaire à une instruction conditionnelle if
. Avec l'instruction if
, à condition que la condition fournie par l'utilisateur soit évaluée à true
, le code dans le corps de l'instruction if
est exécuté une fois .
Mais avec la boucle while
, si la condition est évaluée à true
, la boucle commence à parcourir le corps de la boucle. La boucle continuera son itération tant que la condition continuera d'être évaluée à true
.
La boucle while
s'arrête uniquement lorsque la boucle a terminé l'exécution de toutes les instructions dans l'itération en cours et après vérification de la condition, elle est évaluée à false
.
Regardons la syntaxe d'une boucle while...
while condition {
<statement(s)>;
}
Voir? Très similaire à une instruction conditionnelle if
! Aucun bloc else
cependant ;)
Regardons un programme pour mieux comprendre cela.
fn main() {
let mut var = 0;
while var < 3 {
println!("{var}");
var += 1;
}
}
J'ai une variable mutable, var
, avec une valeur initiale de 0. La boucle while
bouclera aussi longtemps que la valeur stockée dans la variable mutable var
est inférieur à 3.
À l'intérieur de la boucle, la valeur de var
est imprimée et plus tard, sa valeur est incrémentée de 1.
Ci-dessous le résultat du code écrit ci-dessus :
0
1
2
La boucle
Rust a une boucle infinie. Oui, un sans condition de démarrage et sans condition d'arrêt. Il continue simplement à tourner en boucle encore et encore jusqu'à l'infini. Mais bien sûr, il comporte des déclencheurs pour arrêter l’exécution de la boucle à partir du code lui-même.
La syntaxe de cette boucle infinie est la suivante :
loop {
<statement(s)>;
}
Ces boucles sont principalement utilisées dans les logiciels GUI où la sortie est une opération explicite.
Avant même de vous donner un exemple, puisque cette boucle est assez particulière, voyons d'abord comment la sortir :p
Pour arrêter l'exécution d'une boucle infinie, le mot-clé break
est utilisé à l'intérieur de la boucle.
Regardons un exemple où seuls les nombres entiers compris entre 0 et 3 (inclus) sont imprimés sur la sortie du programme.
fn main() {
let mut var = 0;
loop {
if var > 3 {
break;
}
println!("{}", var);
var += 1;
}
}
La meilleure façon d'interpréter cet exemple particulier est de le considérer comme une forme inutilement développée d'une boucle while
;)
Vous avez une variable mutable var
avec une valeur initiale de 0 qui est utilisée comme itérateur, en quelque sorte. La boucle infinie commence par une condition if
selon laquelle la valeur de var
doit être supérieure à 3, le mot-clé break
doit être exécuté. Plus tard, comme dans l'exemple précédent de la boucle while
, la valeur de var
est imprimée sur la sortie standard puis sa valeur est incrémentée de 1.
Il produit le résultat suivant :
0
1
2
3
Boucles étiquetées
Disons qu'il y a deux boucles infinies, l'une imbriquée dans l'autre. Pour une raison quelconque, la condition de sortie est vérifiée dans la boucle la plus interne, mais cette condition de sortie sert à sortir de la boucle la plus externe.
Dans un tel cas, l’étiquetage de la ou des boucles peut être bénéfique.
L'utilisation des labels
break
et des mots-cléscontinue
ne sont pas exclusifs à la boucle infinie. Ils peuvent être utilisés avec les trois boucles proposées par le langage Rust.
Voici comment étiqueter une boucle.
'label: loop {}
Pour indiquer au compilateur qu'une boucle est étiquetée, commencez par un guillemet simple, tapez son étiquette et faites-la suivre de deux points. Ensuite, continuez avec la façon dont vous définissez régulièrement une boucle.
Lorsque vous devez rompre certaines boucles, spécifiez simplement le label de la boucle comme ceci :
break 'label;
Jetons un coup d'œil à un exemple pour mieux comprendre cela.
fn main() {
let mut a = 0;
let mut b = 0;
'parent: loop {
a += 1;
loop {
println!("a: {}, b: {}", a, b);
b += 1;
if a + b == 10 {
println!("\n{} + {} = 10", a, b);
break 'parent;
}
}
}
}
Ici, j'ai pris deux variables mutables a
et b
avec les valeurs initiales définies sur 0 pour les deux.
Plus loin, la boucle la plus externe est étiquetée parent
. La boucle 'parent' incrémente la valeur de la variable a
de 1 et possède une boucle interne/enfant.
Cette boucle enfant (à la ligne 8) imprime les valeurs des variables a
et b
. À l'intérieur de cette boucle, la valeur de b
est incrémentée de 1. Et la condition de sortie est que a + b == 10
. Cela signifie que chaque fois que les valeurs stockées dans les variables a
et b
, lorsqu'elles sont additionnées, donnent 10, la boucle parent
est rompue. Même si la condition break
de la ligne 14 "appartient" à la boucle interne, elle rompt la boucle parent
.
Regardons maintenant le résultat du programme.
a: 1, b: 0
a: 1, b: 1
a: 1, b: 2
a: 1, b: 3
a: 1, b: 4
a: 1, b: 5
a: 1, b: 6
a: 1, b: 7
a: 1, b: 8
1 + 9 = 10
Comme le montre la sortie du programme, la boucle s'arrête dès que a
et b
ont respectivement les valeurs 1 et 9.
Le mot-clé continuer
Si vous avez déjà utilisé des boucles dans un autre langage de programmation comme C/C++/Java/Python, vous connaissez peut-être déjà l'utilisation du mot-clé continue
.
Alors que le mot-clé break
sert à arrêter complètement l'exécution de la boucle, le mot-clé continue
est utilisé pour "sauter" l'itération actuelle de l'exécution de la boucle et démarrer à l'itération suivante (si les conditions le permettent).
Regardons un exemple pour comprendre comment fonctionne le mot-clé continue
.
fn main() {
for i in 0..10 {
if i % 2 == 0 {
continue;
}
println!("{}", i)
}
}
Dans le code ci-dessus, j'ai une boucle for
qui parcourt des nombres entiers compris entre 0 et 9 (inclus). Dès que la boucle démarre, je mets une vérification conditionnelle pour voir si le nombre est pair ou non. Si le nombre est pair, le mot-clé continue
est exécuté.
Mais si le nombre est impair, il est imprimé sur la sortie du programme.
Examinons d'abord le résultat de ce programme.
1
3
5
7
9
Comme vous pouvez le voir, la boucle semble avoir "continué" même s'il y a clairement des nombres pairs entre 0 et 9. Mais comme j'ai utilisé le mot-clé continue
, l'exécution de la boucle s'est arrêtée lorsque ce mot-clé a été rencontré.
La boucle a ignoré tout ce qui se trouvait en dessous et a continué avec l'itération suivante. C'est pourquoi les nombres pairs ne sont pas imprimés, mais tous les nombres impairs entre 0 et 9 sont imprimés sur la sortie du programme.
Conclusion
Pour conclure ce long article, j'ai démontré l'utilisation de 3 boucles différentes : for
, while
et loop
. J'ai également discuté de deux mots-clés qui affectent le flux de contrôle de ces boucles : break
et continue
.
J'espère que vous comprenez maintenant le cas d'utilisation approprié pour chaque boucle. S'il vous plaît laissez-moi savoir si vous avez des questions.