Salta ai contenuti

Cicli in Rust (loop)

Rust ha tre modi per ripetere il codice: loop, while e for. Questa pagina parla di loop, il più semplice e diretto dei tre: ripete all’infinito finché non gli dici di fermarsi.

fn main() {
let mut count = 0;
loop {
count += 1;
println!("{count}");
if count == 3 {
break;
}
}
}

Output:

1
2
3
▶ Provalo tu

Da solo, loop non si ferma mai: è break che lo fa finire. Senza quel if count == 3 { break; }, questo programma stamperebbe all’infinito.

Ecco una cosa che loop sa fare e while e for no: puoi mettere un valore dopo break, e quel valore diventa il risultato dell’intero ciclo:

fn main() {
let mut count = 0;
let result = loop {
count += 1;
if count == 10 {
break count * 2; // fermati e restituisci un valore
}
};
println!("{result}");
}

Output:

20
▶ Provalo tu

È comodo per cose come «continua a riprovare finché funziona, poi dammi il risultato»: vedrai questo schema nel codice reale più spesso di quanto pensi.

Nota il punto e virgola dopo la } di chiusura del ciclo. L’intero loop { ... } è il lato destro di let result = ...;, quindi l’istruzione let ha bisogno del suo ; alla fine, proprio come let x = 5;.

Se arrivi da un altro linguaggio, potresti scrivere un ciclo infinito come while true { ... }. In Rust funziona, ma il compilatore ti avvisa:

warning: denote infinite loops with `loop { ... }`
--> src/main.rs:5:5
|
5 | while true {
| ^^^^^^^^^^ help: use `loop`

L’avviso (in inglese) ti chiede di indicare i cicli infiniti con loop { ... }. Non è solo una questione di stile. Rust sa che il corpo di un loop viene sempre eseguito, e che l’unico modo per uscirne è un break. Per while true non lo dà per scontato, perché non guarda il valore della condizione. Questo fa una differenza vera quando una variabile riceve il suo valore dentro il ciclo:

fn main() {
let mut n = 1;
let answer; // ancora nessun valore
loop {
if n * n > 50 {
answer = n * n; // assegnala appena prima di uscire
break;
}
n += 1;
}
println!("Il primo quadrato maggiore di 50 è {answer}");
}

Output:

Il primo quadrato maggiore di 50 è 64
▶ Provalo tu

Con loop, Rust vede che l’unico modo di arrivare a println! passa da quel break, quindi answer ha sempre un valore. Cambia loop in while true e ottieni error[E0381]: used binding answer is possibly-uninitialized (la variabile answer potrebbe non essere inizializzata). Il compilatore pensa che il ciclo potrebbe finire senza eseguire affatto l’if.

In pratica, la versione più pulita di questo programma usa break con un valore, che hai visto sopra: let answer = loop { ... break n * n; ... };. In entrambi i casi la lezione è la stessa: quando intendi «per sempre, finché non esco con break», scrivi loop.

loop è la scelta giusta quando non sai in anticipo quante volte ripeterai: stai aspettando che una condizione diventi vera, invece di contare lungo un intervallo o una lista. Per contare o scorrere una collezione, while e for (li vediamo nelle prossime pagine) di solito si leggono meglio.

Usa loop per stampare un conto alla rovescia da 5 a 1, poi stampa Decollo!. Suggerimento: parti da let mut n = 5;, ed esci con break quando n arriva a 0.

Mostra la soluzione
fn main() {
let mut n = 5;
loop {
if n == 0 {
break;
}
println!("{n}...");
n -= 1;
}
println!("Decollo!");
}

Output:

5...
4...
3...
2...
1...
Decollo!
▶ Provalo tu

Il controllo viene per primo, quindi quando n vale 0 il ciclo si ferma prima di stampare 0....

Parti da 1 e continua a raddoppiare. Usa break con un valore per ottenere il primo numero sopra 1000, e conta quanti raddoppi ci sono voluti. Suggerimento: tieni un contatore mut fuori dal ciclo, e scrivi let power = loop { ... };.

Mostra la soluzione
fn main() {
let mut value = 1;
let mut doublings = 0;
let power = loop {
value *= 2;
doublings += 1;
if value > 1000 {
break value;
}
};
println!("{power} dopo {doublings} raddoppi");
}

Output:

1024 dopo 10 raddoppi
▶ Provalo tu

break value; termina il ciclo e consegna value a power. Il contatore vive fuori dal ciclo, quindi conserva il suo valore anche dopo la fine del ciclo.

  • loop ripete all’infinito finché un break non lo ferma: assicurati sempre che ce ne sia uno.
  • break valore; ferma il ciclo e restituisce valore come risultato dell’intera espressione loop.
  • Scrivi loop, non while true: Rust sa che il corpo di un loop viene sempre eseguito, e questo lo aiuta a controllare le tue variabili.
  • Usa loop quando ripeti «finché succede qualcosa», non quando conti un numero di volte già noto.

Verifica veloce

1. Cosa impedisce a un semplice loop di girare all'infinito?

2. Cosa ottieni scrivendo break count * 2; dentro un ciclo?

3. Secondo questa pagina, quando loop è la scelta migliore rispetto a while o for?

4. Cosa succede se scrivi while true { ... } in Rust?

Punteggio: 0 / 4