Rust

Any donation is very welcome
Fork me on GitHub

I. Les bases de la programmation en Rust

7. Les boucles

Nous les avons vu très rapidement à la fin du chapitre précédent donc approfondissons le sujet :

Les boucles sont l'une des bases de programmation, il est donc impératif de regarder comment elles fonctionnent en Rust.

while

Comme dans les autre langages, elle continue tant que sa condition est respectée. Exemple :

Runlet mut i: i32 = 0;

while i < 10 {
    println!("bonjour !");
    i += 1;
}

Ici, le programme affichera bonjour tant que i sera inférieur à 10.

Il faut cependant faire attention à plusieurs choses :

  • Vous noterez encore une fois qu'il n'y a pas de parenthèse autour de la condition !
  • Tout comme pour les conditions, les accolades sont encore une fois obligatoires !

Il existe aussi la possibilité d'écrire des boucles infinies avec le mot clé loop (plutôt qu'un while true) :

loop

Je pense que vous vous demandez tous : "mais à quoi ça peut bien nous servir ?". Prenons un exemple : un jeu-vidéo. L'affichage doit continuer en permanence jusqu'à ce que l'on quitte. Plutôt que d'écrire :

Runwhile true {
    //...
}

// ou

let mut end = false;

while end == false {
    //...
}

On écrira tout simplement :

Runloop {
    //...
}

Maintenant vous vous dites sans doute : "Ok, mais comment on l'arrête cette boucle ?". Tout simplement avec le mot-clé break . Reprenons notre exemple du début :

Runlet mut i: i32 = 0;

loop {
    println!("bonjour !");
    i += 1;
    if i > 10 {
        break;
    }
}

Petit rappel concernant les mots-clés break et return : le mot-clé break permet seulement de quitter la boucle courante :

Runloop {
    println!("Toujours là !");
    let mut i = 0i32;

    loop {
        println!("sous-boucle !");
        i += 1;
        if i > 2 {
            break; // et on revient dans la boucle précédente
        }
    }
}

Tandis que le mot-clé return fait quitter la fonction courante :

Runfn main() {
    loop {
        println!("Toujours là !");
        let mut i = 0i32;

        loop {
            println!("sous-boucle !");
            i += 1;
            if i > 2 {
                return; // on quitte la fonction main et donc le programme se termine
            }
        }
    }
}

for

La boucle for est un peu plus complexe que les deux précédentes. Elle ne fonctionne qu'avec des objets implémentant le trait IntoIterator. Vous ne savez pas ce qu'est un trait ? Pour le moment ce n'est pas important, nous y reviendrons plus tard. Prenons maintenant des exemples de comment fonctionne la boucle for :

Runfor i in 0..10 {
    println!("i vaut : {}", i);
}

Ce qui va afficher :

i vaut : 0
i vaut : 1
i vaut : 2
i vaut : 3
i vaut : 4
i vaut : 5
i vaut : 6
i vaut : 7
i vaut : 8
i vaut : 9

Comme vous l'aurez compris la variable i, créée pour la boucle for, prendra successivement toutes les valeurs allant de 0 à 9 puis la boucle s'arrêtera toute seule.

Certains d'entre vous doivent se demander si je n'ai pas menti en disant que la boucle for ne s'utilisait que sur des objets en voyant ce "0..10". Hé bien sachez que non, ce "0..10" est considéré comme un objet de type Range qui implémente le trait IntoIterator. J'insiste sur le fait que c'est tout à fait normal si vous ne comprenez pas toutes mes explications pour l'instant !

Prenons un deuxième exemple :

Runlet v = vec!(1, 4, 5, 10, 6);

for value in v {
    println!("{}", value);
}

Ce qui va afficher :

1
4
5
10
6

Énumération

Si vous souhaitez savoir combien de fois vous avez itéré, vous pouvez utiliser la fonction enumerate :

Runfor (i, j) in (5..10).enumerate() {
    println!("i = {} et j = {}", i, j);
}

Ce qui affichera :

i = 0 et j = 5
i = 1 et j = 6
i = 2 et j = 7
i = 3 et j = 8
i = 4 et j = 9

i vaut donc le nombre d'itérations effectuées à l'intérieur de la boucle tandis que j prend successivement les valeur range. Autre exemple :

Runlet v = vec!("a", "b", "c", "d");

for (i, value) in v.iter().enumerate() {
    println!("i = {} et value = \"{}\"", i, value);
}

Les boucles nommées

Encore une autre chose intéressante à connaître : les boucles nommées ! Mieux vaut commencer par un exemple :

Run'outer: for x in 0..10 {
    'inner: for y in 0..10 {
        if x % 2 == 0 { continue 'outer; } // on continue la boucle sur x
        if y % 2 == 0 { continue 'inner; } // on continue la boucle sur y
        println!("x: {}, y: {}", x, y);
    }
}

Je pense que vous l'aurez compris, on peut directement reprendre ou arrêter une boucle en utilisant son nom (pour peu que vous lui en ayez donné un bien évidemment). Autre exemple :

Run'global: for _ in 0..10 {
    'outer: for x in 0..10 {
        'inner: for y in 0..10 {
            if x > 3 { break 'global; } // on arrête la boucle qui s'appelle global
            if x % 2 == 0 { continue 'outer; } // on continue la boucle sur x
            if y % 2 == 0 { continue 'inner; } // on continue la boucle sur y
            println!("x: {}, y: {}", x, y);
        }
    }
}

Encore une fois, je vous invite à tester pour bien comprendre comment tout ça fonctionne. Quand ce sera bon, il sera temps de passer aux fonctions !