for … in în Rust

Parcurge pe rând fiecare element al unui interval, al unei colecții sau al unui iterator.

Sintaxă
for element in colectie { ... }
for i in 0..n { ... }         // 0, 1, ..., n-1
for i in 1..=n { ... }        // 1, 2, ..., n
for x in &v { ... }           // prin referință
for x in &mut v { ... }       // prin referință mutabilă

Ce face for … in

for x in ceva funcționează cu orice valoare care se poate transforma într-un iterator: intervale (0..10), array-uri, vectori, HashMap, caracterele unui text (s.chars()) și orice iterator. Rust nu are bucla for (i = 0; i < n; i++) din C.

a..b merge de la a la b - 1, iar a..=b include și b. Pentru ordine inversă: (1..=10).rev(); pentru pași mai mari: (0..100).step_by(10).

Atenție la ce primește bucla: for x in v consumă vectorul (după buclă v nu mai poate fi folosit), for x in &v doar îl citește, iar for x in &mut v îți permite să modifici elementele cu *x. Pentru indice și valoare împreună, folosește .iter().enumerate().

Exemple

Exemplul 1: Intervale

1..=5 include 5. rev() inversează ordinea, iar step_by sare din 5 în 5.

fn main() {
    for i in 1..=5 {
        print!("{i} ");
    }
    println!();
    for i in (1..=3).rev() {
        print!("{i}... ");
    }
    println!("Start!");
    let multipli: Vec<i32> = (0..=20).step_by(5).collect();
    println!("{multipli:?}");
}

Rezultat

1 2 3 4 5 
3... 2... 1... Start!
[0, 5, 10, 15, 20]

Exemplul 2: Prin referință, cu indice, și cu modificare

&elevi doar citește, deci vectorul poate fi folosit și după buclă. enumerate dă perechi (indice, element). &mut note permite modificarea fiecărei note prin *nota.

fn main() {
    let elevi = vec!["Ana", "Mihai", "Ioana"];
    for (i, nume) in elevi.iter().enumerate() {
        println!("{}. {nume}", i + 1);
    }

    let mut note = vec![7, 8, 9];
    for nota in &mut note {
        *nota += 1;
    }
    println!("{} elevi, note mărite: {note:?}", elevi.len());
}

Rezultat

1. Ana
2. Mihai
3. Ioana
3 elevi, note mărite: [8, 9, 10]

Exemplul 3: Caracterele unui text

chars() dă caracterele unul câte unul, inclusiv cele cu diacritice.

fn main() {
    let cuvant = "Brașov";
    let mut vocale = 0;
    for c in cuvant.chars() {
        if "aeiouăâî".contains(c.to_ascii_lowercase()) {
            vocale += 1;
        }
    }
    println!("{cuvant} are {} caractere, dintre care {vocale} vocale", cuvant.chars().count());
}

Rezultat

Brașov are 6 caractere, dintre care 2 vocale

Greșeli frecvente

  • Scrii for x in v și apoi folosești v: eroare borrow of moved value, pentru că bucla a consumat vectorul. Scrie for x in &v.
  • Parcurgi după indice (for i in 0..v.len()) doar ca să citești v[i]. Varianta for x in &v sau .iter().enumerate() este mai sigură și mai rapidă (fără verificarea indicelui).
  • Încerci să adaugi sau să ștergi elemente din vector în timp ce îl parcurgi. Compilatorul nu permite (vectorul este împrumutat de buclă); colectează modificările și aplică-le după buclă sau folosește retain.

Comenzi înrudite

  • 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.
  • 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.
  • array ([T; N]): Un șir de lungime fixă, cunoscută la compilare, cu elemente de același tip, păstrat direct pe stivă.
  • slice-uri (&[T] și &str): O „fereastră” spre o parte dintr-un array, Vec sau text: o referință care știe de unde începe și câte elemente are, fără să copieze nimic.
  • closures și move: Funcții anonime, scrise cu |parametri|, care pot folosi variabilele din jur. move le dă proprietatea asupra acelor variabile.