Completiamo l'introduzione alla tematica fondamentale del controllo di flusso in Rust, integrando quanto visto nella lezione precedente con un altro grande argomento: i cicli. Tali costrutti sono comuni ad altri linguaggi come Java e Python.
Questi, anche in Rust, come un po' in tutti i linguaggi di programmazione, prendono la forma delle due parole chiave for
e while
. Sebbene qui ne troveremo anche altre.
Il costrutto while in Rust
Con il while
si introduce un blocco di operazioni che viene ripetuto finché la condizione booleana specificata permane vera. Ad esempio, diciamo che vogliamo stampare tutti i numeri da 1 a 10 inclusi. Avremo bisogno di una variabile che farà da contatore, di un blocco di codice per l'operazione di stampa e, da non dimenticare pena l'avvio di un ciclo infinito, un incremento del contatore nel blocco che ad ogni iterazione ci farà avvicinare alla fine del ciclo:
let mut contatore=1;
while contatore
Il ciclo for in Rust
Lo stesso risultato del paragrafo precedente si potrebbe ottenere con il costrutto for..in
, specializzato nell'interazione su un range di valori:
for contatore in 1..=10{
println!("... {}", contatore);
}
Si noti che non è stato nemmeno necessario dichiarare la variabile contatore
che verrà direttamente creata dal ciclo ma non sarà più disponibile dopo il suo termine. In pratica, il contatore nasce e muore con il ciclo.
Si noti ancora che abbiamo utilizzato la notazione 1..=10
per indicare gli estremi del range. Il simbolo uguale (=
) serve a specificare che il valore 10 è incluso nell'intervallo ed infatti il relativo messaggio sarà stampato. Avremmo potuto anche escludere tale valore dal range terminando le iterazioni nel momento in cui il contatore avrebbe raggiunto il valore 9. Per farlo sarebbe stato sufficiente rimuovere l'uguale specificando la notazione 1..10
.
La parola chiave loop
Sinora abbiamo visto con while
e for
due casi in cui la condizione o l'intervallo di valori viene subito posto all'inizio del costrutto. In molti casi però si ha necessità di creare un ciclo che prosegua finché all'interno del suo blocco di codice non maturi la condizione idonea a portarlo alla sua fine. Per questa casistica, assai comune a dire il vero, in Rust esiste la parola chiave loop
che viene seguita semplicemente da un blocco di codice:
loop {
// istruzioni da eseguire
}
Ciò potrebbe dare l'impressione di un ciclo infinito se non fosse per l'esistenza di altre due parole chiave, continue
e break
, che rispettivamente innescano l'iterazione successiva (con contestuale abbandono di quella in corso) o la fine del ciclo con la prosecuzione del programma.
Nell'esempio che segue, vediamo un ciclo loop
che stampa solo i numeri dispari uscendo dal ciclo non appena si è superato il numero 10 (lo stesso risultato si sarebbe potuto ottenere in modi diversi e più semplici ma questo approccio è servito per trattare tutte le parole chiave in questione):
let mut contatore=1;
loop {
contatore+=1;
if contatore%2==0 {
// numero pari passiamo alla prossima iterazione
continue;
}
else
{
// numero dispari, lo stampiamo
println!("... {}", contatore);
}
if contatore>10 {
// superato 10, abbandoniamo il ciclo
break;
}
} // fine di loop
L'output ottenuto è il seguente:
... 3
... 5
... 7
... 9
... 11
Dopo il break
, l'esecuzione supererà il ciclo e proseguirà normalmente con le righe ad esso successive qualora ve ne siano.
Esempio: le tabelline
Concludiamo la lezione con un esempio, piuttosto classico, che porta alla stampa della tabellina di un numero specificato. Dovendo applicare la stessa operazione a tutti i valori di un range adotteremo l'approccio del for..in
:
let tabellina_del=5;
for contatore in 1..=10{
println!("{} X {} = {}", tabellina_del, contatore, tabellina_del*contatore)
}
Otteniamo così, con queste poche semplici righe, il risultato che ci interessa ovvero la stampa della tabellina del 5:
5 X 1 = 5
5 X 2 = 10
5 X 3 = 15
5 X 4 = 20
5 X 5 = 25
5 X 6 = 30
5 X 7 = 35
5 X 8 = 40
5 X 9 = 45
5 X 10 = 50
Sebbene questo sia un caso ottimo per il for
, a titolo di confronto lo faremo anche con il while
:
let tabellina_del=5;
let mut contatore=1;
while contatore
Da notare che nonostante il risultato sia lo stesso, quest'ultimo esempio ha richiesto qualche riga in più in quanto abbiamo dovuto dichiarare il contatore, mutabile, e provvedere al suo incremento alla fine del blocco di codice.