Ciclo Loop in Rust
In Rust, loop crea un ciclo infinito che continua a ripetere un blocco di codice fino a quando non viene interrotto esplicitamente con break. A differenza di while true in altri linguaggi, loop è il modo idiomatico di Rust per esprimere un ciclo che non ha una condizione di uscita naturale. Il compilatore sa che il ciclo viene eseguito almeno una volta, il che permette ottimizzazioni e inferenze di tipo più precise.
Loop infinito di base
La forma più semplice di loop ripete il blocco all’infinito.
fn main() {
loop {
println!("Questo messaggio si ripete all'infinito!");
}
}
Questo codice stamperà il messaggio indefinitamente. In un programma reale, un ciclo del genere viene sempre interrotto tramite break o da logica esterna.
Interrompere con break
La parola chiave break interrompe l’esecuzione del ciclo e fa proseguire il programma con l’istruzione successiva al loop.
fn main() {
let mut contatore = 0;
loop {
contatore += 1;
if contatore == 5 {
println!("Raggiunto il valore 5, esco dal ciclo");
break;
}
println!("Contatore: {contatore}");
}
println!("Ciclo terminato");
}
L’output sarà :
Contatore: 1
Contatore: 2
Contatore: 3
Contatore: 4
Raggiunto il valore 5, esco dal ciclo
Ciclo terminato
Saltare un’iterazione con continue
La parola chiave continue salta il resto del blocco corrente e passa alla prossima iterazione del ciclo.
fn main() {
let mut i = 0;
loop {
i += 1;
if i > 10 {
break;
}
if i % 2 != 0 {
continue;
}
println!("{i} è pari");
}
}
Restituire valori dal loop
Una caratteristica unica di Rust è che loop può restituire un valore tramite break. Questo è molto utile quando il loop viene usato per calcolare un risultato.
fn main() {
let mut contatore = 0;
let risultato = loop {
contatore += 1;
if contatore == 10 {
break contatore * 2;
}
};
println!("Il risultato è: {risultato}"); // Stampa: Il risultato è: 20
}
Il valore passato a break diventa il valore restituito dall’intera espressione loop. Questo pattern è particolarmente utile per operazioni di retry o ricerca:
fn main() {
let numeri = [2, 7, 15, 3, 42, 8];
let mut indice = 0;
let trovato = loop {
if indice >= numeri.len() {
break None;
}
if numeri[indice] > 10 {
break Some(numeri[indice]);
}
indice += 1;
};
match trovato {
Some(n) => println!("Primo numero maggiore di 10: {n}"),
None => println!("Nessun numero maggiore di 10 trovato"),
}
}
Label per loop annidati
Quando si hanno loop annidati, le label permettono di specificare quale ciclo interrompere con break o quale ciclo far avanzare con continue. Le label iniziano con un apostrofo (').
fn main() {
let mut esterno = 0;
'ciclo_esterno: loop {
let mut interno = 0;
loop {
if interno == 3 {
esterno += 1;
break; // Esce solo dal ciclo interno
}
if esterno == 2 {
println!("Esco da entrambi i cicli");
break 'ciclo_esterno; // Esce dal ciclo esterno
}
println!("esterno: {esterno}, interno: {interno}");
interno += 1;
}
}
}
Le label possono essere combinate con il ritorno di valori:
fn main() {
let mut x = 0;
let valore = 'esterno: loop {
let mut y = 0;
loop {
if x + y == 5 {
break 'esterno (x, y);
}
y += 1;
if y > x {
break;
}
}
x += 1;
if x > 10 {
break 'esterno (0, 0);
}
};
println!("Trovata la coppia: ({}, {})", valore.0, valore.1);
}
Pattern comuni con loop
Un uso frequente di loop è nei menu interattivi o nei cicli di input:
use std::io;
fn main() {
loop {
println!("\n--- Menu ---");
println!("1. Saluta");
println!("2. Esci");
let mut scelta = String::new();
io::stdin().read_line(&mut scelta).expect("Errore di lettura");
match scelta.trim() {
"1" => println!("Ciao!"),
"2" => {
println!("Arrivederci!");
break;
}
_ => println!("Scelta non valida"),
}
}
}
Conclusione
Il ciclo loop è lo strumento ideale in Rust quando si necessita di un ciclo senza condizione di uscita predefinita. La possibilita di restituire valori tramite break e l’uso delle label per gestire loop annidati lo rendono uno strumento potente e flessibile. Quando la condizione di terminazione è nota in anticipo, considera l’uso di while o for come alternative più appropriate.