Acheter version papier

Rust

Fork me on GitHub

I. Les bases de la programmation en Rust

11. if let / while let

Maintenant que nous avons vu ce qu'étaient les enums, je peux vous parler de if let et de while let.

Qu'est-ce que le if let ?

Le if let permet de simplifier certains traitements de pattern matching. Prenons un exemple :

Runfn fais_quelque_chose(i: i32) -> Option<String> {
    if i < 10 {
        Some("variable inférieure à 10".to_owned())
    } else {
        None
    }
}

Normalement, pour vérifier le retour de cette fonction, vous utiliseriez un match :

Runmatch fais_quelque_chose(1) {
    Some(s) => println!("{}", &s),
    None => {} // rien à afficher donc on ne fait rien
}

Et bien avec le if let vous pouvez faire :

Runif let Some(s) = fais_quelque_chose(1) {
    println!("{}", &s)
}

Et c'est tout. Pour faire simple, si le type renvoyé par la fonction fais_quelque_chose correspond à celui donné au if let, le code du if sera exécuté. On peut bien évidemment le coupler avec un else if ou avec un else :

Runif let Some(s) = fais_quelque_chose(1) {
    println!("{}", &s)
} else {
    println!("il ne s'est rien passé")
}

Essayez en passant un nombre supérieur à 10 comme argument, vous devriez rentrer dans le else.

D'ailleurs, je ne l'ai pas précisé dans le chapitre "Conditions et pattern matching" mais il est possible d'être plus précis dans le pattern matching en utilisant plusieurs niveaux de types. Par exemple :

Runlet x = Some(10);

// on rentre dans ce if si x est un Option::Some contenant 10 !
if let Some(10) = x {
    // ...
} else if let Some(11) = x {
    // ...
}

Vous pouvez bien évidemment le faire sur autant de "niveaux" que vous le souhaitez :

Runlet x = Ok(Some(Ok(Ok(2))));

if let Ok(Some(Ok(Ok(2)))) = x {
    // ...
}

while let

Le while let fonctionne de la même façon : tant que le type renvoyé correspondra au type attendu, la boucle continuera. Donc le code suivant :

Runlet mut v = vec!(1, 2, 3);

loop {
    match v.pop() {
        Some(x) => println!("{}", x),
        None => break,
    }
}

Deviendra :

Runlet mut v = vec!(1, 2, 3);

while let Some(x) = v.pop() {
    println!("{}", x);
}

Déstructuration

Dans le précédent chapitre, je vous ai rapidement montré ce qu'était la déstructuration. Cela fonctionne bien évidemment pour while let et if let :

Runstruct Point {
    x: i32,
    y: i32,
}

let origin = Point { x: 0, y: 0 };

match origin {
    Point { x, y } => println!("({},{})", x, y),
}
// est équivalent à :
if let Point { x, y } = origin {
    println!("({},{})", x, y);
}