00
:
00
:
00
:
00
•Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

Break e Continue in Rust

In Rust, break e continue sono parole chiave usate per controllare il flusso di esecuzione all’interno dei cicli. break interrompe il ciclo, mentre continue salta alla prossima iterazione. Rust aggiunge una potenza espressiva unica grazie alle label, che permettono di controllare cicli annidati, e alla possibilita di restituire valori con break.

Break nei cicli

La parola chiave break interrompe immediatamente l’esecuzione del ciclo in cui si trova. L’esecuzione prosegue con la prima istruzione dopo il ciclo.

fn main() {
    for i in 0..100 {
        if i == 5 {
            println!("Trovato 5, esco dal ciclo");
            break;
        }
        println!("i = {i}");
    }
    println!("Ciclo terminato");
}

break funziona in tutti i tipi di ciclo: loop, while e for.

fn main() {
    let mut n = 0;

    while n < 100 {
        if n * n > 50 {
            println!("Il primo quadrato maggiore di 50 è {}", n * n);
            break;
        }
        n += 1;
    }
}

Continue nei cicli

La parola chiave continue salta il resto del corpo del ciclo corrente e passa direttamente alla prossima iterazione.

fn main() {
    for i in 1..=20 {
        if i % 3 == 0 {
            continue; // Salta i multipli di 3
        }
        println!("{i}");
    }
}

Un esempio pratico: filtrare valori durante un’elaborazione:

fn main() {
    let dati = vec![Some(10), None, Some(20), None, Some(30)];

    let mut somma = 0;
    for dato in &dati {
        let Some(valore) = dato else {
            continue; // Salta i None
        };
        somma += valore;
    }

    println!("Somma dei valori presenti: {somma}");
}

Label per cicli annidati

Quando si hanno cicli annidati, break e continue agiscono solo sul ciclo più interno. Per controllare un ciclo esterno, si usano le label. Una label inizia con un apostrofo (') seguito da un identificatore e da due punti.

fn main() {
    'esterno: for i in 0..5 {
        for j in 0..5 {
            if i + j == 6 {
                println!("Somma 6 trovata con i={i}, j={j}");
                break 'esterno;
            }
        }
    }

    println!("Fuori da entrambi i cicli");
}

Senza la label 'esterno, il break avrebbe interrotto solo il ciclo interno su j.

Continue con label

Anche continue supporta le label per saltare all’iterazione successiva di un ciclo esterno.

fn main() {
    'riga: for i in 0..5 {
        for j in 0..5 {
            if j == 2 {
                continue 'riga; // Salta all'iterazione successiva del ciclo esterno
            }
            print!("({i},{j}) ");
        }
        println!(); // Questa riga non viene mai raggiunta se j raggiunge 2
    }
}

Ogni riga dell’output mostrerà solo (i,0) (i,1) perche quando j arriva a 2, il continue 'riga passa direttamente all’iterazione successiva del ciclo esterno.

Uscire da cicli annidati multipli

Le label sono essenziali quando si hanno tre o più livelli di annidamento:

fn main() {
    let matrice_3d = [
        [[1, 2], [3, 4]],
        [[5, 6], [7, 8]],
    ];

    let obiettivo = 7;

    'livello1: for piano in &matrice_3d {
        for riga in piano {
            for &valore in riga {
                if valore == obiettivo {
                    println!("Trovato {obiettivo}!");
                    break 'livello1;
                }
            }
        }
    }
}

Restituire valori con break etichettato

In Rust, loop permette di restituire un valore tramite break. Questa funzionalita si combina con le label per restituire un valore da un loop annidato specifico.

fn main() {
    let risultato = 'cerca: loop {
        for i in 0..100 {
            if i * i > 200 {
                break 'cerca i;
            }
        }
        break 'cerca -1;
    };

    println!("Primo intero il cui quadrato supera 200: {risultato}");
}

Un esempio più complesso con ricerca su griglia:

fn main() {
    let griglia = vec![
        vec![1, 2, 3],
        vec![4, 5, 6],
        vec![7, 8, 9],
    ];

    let trovato = 'ricerca: {
        for (r, riga) in griglia.iter().enumerate() {
            for (c, &valore) in riga.iter().enumerate() {
                if valore == 5 {
                    break 'ricerca Some((r, c));
                }
            }
        }
        None
    };

    match trovato {
        Some((r, c)) => println!("Valore trovato alla riga {r}, colonna {c}"),
        None => println!("Valore non trovato"),
    }
}

Pattern comuni

Ciclo con tentativo limitato

fn main() {
    let mut tentativi = 0;
    let max_tentativi = 5;

    let successo = loop {
        tentativi += 1;
        println!("Tentativo {tentativi}...");

        // Simula un'operazione che potrebbe fallire
        let riuscito = tentativi == 3;

        if riuscito {
            break true;
        }

        if tentativi >= max_tentativi {
            break false;
        }
    };

    if successo {
        println!("Operazione riuscita al tentativo {tentativi}");
    } else {
        println!("Operazione fallita dopo {max_tentativi} tentativi");
    }
}

Processare fino a condizione specifica

fn main() {
    let valori = vec![3, 7, 2, 8, 1, 9, 4, 6];

    for &v in &valori {
        if v > 8 {
            println!("Trovato valore fuori range: {v}");
            break;
        }
        println!("Processato: {v}");
    }
}

Conclusione

break e continue sono strumenti fondamentali per controllare il flusso all’interno dei cicli in Rust. Le label aggiungono la possibilita di gestire cicli annidati con precisione, e la capacita di restituire valori tramite break rende i pattern di ricerca e calcolo iterativo molto piu eleganti. Usa le label con parsimonia: spesso una funzione separata con un return anticipato rende il codice più leggibile rispetto a label su molti livelli di annidamento.