while let în Rust

Repetă un bloc cât timp o valoare se potrivește cu un tipar, de exemplu cât timp pop() mai returnează Some.

Sintaxă
while let Tipar = expresie {
    ...                    // se repetă cât timp tiparul se potrivește
}

Ce face while let

while let combină o buclă cu if let: la fiecare pas evaluează expresia și, dacă rezultatul se potrivește cu tiparul, execută corpul cu variabilele scoase din tipar. Bucla se oprește la prima nepotrivire.

Cel mai des este folosit cu metode care returnează Option: while let Some(x) = stiva.pop() golește o stivă, while let Some(linie) = linii.next() parcurge un iterator pe care îl controlezi manual, iar while let Ok(mesaj) = canal.recv() primește mesaje până se închide canalul.

Spre deosebire de for, expresia este reevaluată la fiecare pas, deci poți modifica structura în corp (de exemplu să adaugi elemente noi în stivă).

Exemple

Exemplul 1: Golirea unei stive

pop() returnează Some(element) cât timp vectorul mai are elemente și None când este gol. Elementele ies în ordine inversă.

fn main() {
    let mut farfurii = vec!["albastră", "verde", "roșie"];
    while let Some(f) = farfurii.pop() {
        println!("Spăl farfuria {f}");
    }
    println!("Rămase: {}", farfurii.len());
}

Rezultat

Spăl farfuria roșie
Spăl farfuria verde
Spăl farfuria albastră
Rămase: 0

Exemplul 2: O coadă la care se adaugă în timpul buclei

Parcurgerea unei organigrame: fiecare șef scos din coadă își adaugă subalternii la final. Bucla continuă până când coada se golește.

use std::collections::VecDeque;

fn subalterni(nume: &str) -> Vec<&'static str> {
    match nume {
        "Director" => vec!["Vânzări", "IT"],
        "IT" => vec!["Ana", "Mihai"],
        "Vânzări" => vec!["Ioana"],
        _ => vec![],
    }
}

fn main() {
    let mut coada = VecDeque::from(["Director"]);
    while let Some(nume) = coada.pop_front() {
        let sub = subalterni(nume);
        println!("{nume} -> {sub:?}");
        coada.extend(sub);
    }
}

Rezultat

Director -> ["Vânzări", "IT"]
Vânzări -> ["Ioana"]
IT -> ["Ana", "Mihai"]
Ioana -> []
Ana -> []
Mihai -> []

Greșeli frecvente

  • Folosești while let Some(x) = v.iter().next(). La fiecare pas se creează un iterator nou, deci next() dă mereu primul element și bucla nu se termină. Creează iteratorul o singură dată, înainte de buclă, sau folosește for.
  • Folosești while let doar ca să parcurgi o colecție pe care nu o modifici; for x in &v este mai simplu.

Comenzi înrudite

  • while: Repetă un bloc de cod cât timp o condiție bool rămâne adevărată; condiția este verificată înainte de fiecare pas.
  • if let și let else: if let execută un bloc doar dacă o valoare se potrivește cu un tipar; let else desface valoarea sau iese imediat din funcție.
  • loop, break și continue: loop repetă un bloc la nesfârșit până la un break; break poate returna o valoare, iar continue sare la pasul următor al buclei.
  • pattern matching (tipare): Tiparele descriu forma unei valori și scot din ea părțile de care ai nevoie: în let, match, if let, for și parametrii funcțiilor.