Ciclo for in Rust
for scorre un range o una collezione, un elemento alla volta. Dei tre tipi di ciclo di Rust, è quello che userai più spesso.
Scorrere un range
Sezione intitolata “Scorrere un range”fn main() { for i in 1..=5 { println!("{i}"); }}Output:
123451..=5 è un range (intervallo) che include entrambi gli estremi (da 1 a 5). Se togli l’=, cioè 1..5, si ferma un passo prima e ti dà i numeri da 1 a 4. È facile inciampare in questo errore «di uno», quindi conviene controllare due volte quale dei due intendevi.
Scorrere una collezione
Sezione intitolata “Scorrere una collezione”Qui for dà il meglio di sé: scorre un array o un vettore senza che tu debba tenere traccia di un indice:
fn main() { let fruits = ["mela", "banana", "ciliegia"];
for fruit in fruits { println!("{fruit}"); }}Output:
melabananaciliegiaConfrontalo con il contare a mano in un ciclo while e usare un indice (fruits[i]): è più corto e non c’è nessun indice da sbagliare. Approfondirai array e vettori nelle pagine Array e Vettori.
Avere anche l’indice con .enumerate()
Sezione intitolata “Avere anche l’indice con .enumerate()”Se ti servono sia la posizione sia il valore, usa .enumerate():
fn main() { let fruits = ["mela", "banana", "ciliegia"];
for (index, fruit) in fruits.iter().enumerate() { println!("{index}: {fruit}"); }}Output:
0: mela1: banana2: ciliegiaLa parte (index, fruit) è un pattern di tupla: a ogni giro ricevi una coppia, e il ciclo la divide per te in due variabili.
Contare all’indietro e a salti
Sezione intitolata “Contare all’indietro e a salti”E se vuoi contare alla rovescia da 3, o visitare solo un numero sì e uno no? Il primo tentativo naturale è un range che va all’indietro, come 3..=1. Compila, ma il ciclo non gira mai. Un range conta solo in avanti, quindi un range con l’inizio più grande della fine è semplicemente vuoto.
Prendi invece un range normale e cambia il modo in cui lo percorri:
.rev()percorre il range al contrario..step_by(n)prende un valore ognin, a partire dal primo.
fn main() { for i in (1..=3).rev() { println!("{i}..."); } println!("Via!");
for even in (0..=10).step_by(2) { print!("{even} "); } println!();
for i in 3..=1 { println!("questo non viene mai stampato: {i}"); }}Output:
3...2...1...Via!0 2 4 6 8 10Fai caso alle parentesi: (1..=3).rev(). Senza, Rust leggerebbe 1..=3.rev() come «da 1 fino a 3.rev()», che non è quello che vuoi. Puoi anche combinare le due cose: (0..=10).rev().step_by(5) dà 10, 5, 0.
Perché per contare si preferisce for a while
Sezione intitolata “Perché per contare si preferisce for a while”Potresti scrivere un ciclo che conta con while, ma for con un range elimina un’intera categoria di errori: nessun contatore manuale da dimenticare di aggiornare e nessun rischio di andare un passo oltre la fine di un array. Chi programma in Rust usa for di default e ricorre a while solo quando non c’è un range o una collezione naturale da scorrere.
Pratica
Sezione intitolata “Pratica”1. Una tabellina
Sezione intitolata “1. Una tabellina”Stampa la tabellina del 7, da 7 x 1 = 7 fino a 7 x 10 = 70. Suggerimento: basta un ciclo for su 1..=10. Puoi fare la moltiplicazione direttamente dentro println!.
Mostra la soluzione
fn main() { for i in 1..=10 { println!("7 x {i} = {}", 7 * i); }}Output:
7 x 1 = 77 x 2 = 147 x 3 = 217 x 4 = 287 x 5 = 357 x 6 = 427 x 7 = 497 x 8 = 567 x 9 = 637 x 10 = 70Le variabili con un nome, come {i}, possono andare direttamente tra le graffe. Un calcolo come 7 * i no, quindi si usa una {} vuota con il valore dopo la virgola.
2. Somma i numeri dispari
Sezione intitolata “2. Somma i numeri dispari”Somma tutti i numeri dispari da 1 a 99 e stampa il totale. Suggerimento: (1..100).step_by(2) ti dà 1, 3, 5, … 99. Tieni un totale mut fuori dal ciclo.
Mostra la soluzione
fn main() { let mut total = 0;
for n in (1..100).step_by(2) { total += n; }
println!("La somma dei numeri dispari da 1 a 99 è {total}");}Output:
La somma dei numeri dispari da 1 a 99 è 2500Un altro modo è scorrere 1..100 e sommare n solo quando n % 2 == 1. Funzionano entrambi. step_by salta semplicemente i numeri pari invece di controllarli uno per uno.
Riepilogo
Sezione intitolata “Riepilogo”for elemento in range_o_collezione { ... }è il ciclo di tutti i giorni in Rust.1..=5include entrambi gli estremi;1..5si ferma prima del 5.- Scorri direttamente array e vettori per avere ogni valore senza indici manuali.
- Usa
.enumerate()quando ti serve l’indice insieme al valore. - Un range all’indietro come
3..=1è vuoto. Usa(1..=3).rev()per contare alla rovescia e.step_by(n)per saltare valori.
Verifica veloce
Sezione intitolata “Verifica veloce”Verifica veloce
1. Che differenza c'è tra 1..=5 e 1..5 in un ciclo for?
2. Come ottieni sia l'indice sia il valore mentre scorri una collezione?
3. Perché in genere si preferisce for a while per scorrere una collezione?
4. Che cosa fa for i in 5..=1 { ... }?
Punteggio: 0 / 4
Per approfondire
Sezione intitolata “Per approfondire”- Looping Through a Collection with for — The Rust Book (in inglese): l’introduzione ufficiale, con un conto alla rovescia usando
.rev(). - for and range — Rust by Example (in inglese): esempi eseguibili con i range, più
iter,iter_muteinto_iterper le collezioni. - Iterator loops — The Rust Reference (in inglese): le regole esatte di quello che fa un ciclo
fordietro le quinte. Iterator::step_by— documentazione della libreria standard (in inglese): come funzionastep_by, con esempi.revè documentato nella stessa pagina.