Rust - ciclo while
Il primo dei comandi di iterazione che incontriamo è il ben noto, nel
mondo della programmazione while. Il format a livello sintattico è molto
semplice:while condizione {
istruzioni
}
nel quale il blocco di istruzioni viene iterato fintantochè la condizione (booleana ovviamente) è verificata. Se la condizione è sempre verificata ovviamente abbiamo un ciclo infinito. Se non è mai verificata le istruzioni all'interno del while non saranno mai eseguite. Esempio semplicissimo:
Esempio 19.1
fn main() {
let mut x = 0;
while x < 5 {
println!("ciao");
x = x + 1;
}
}
che stampa 5 volte a video la stringa "ciao". Fondamentale è l'istruzione
di incremento della variabile xx = x + 1;
Senza tale incremento
l'iterazione introdotta dal while non avrebbe fine. Il valore di x alla fine
sarà 5 e la variabile ancora riutilizzabile. Se proprio volete un ciclo
infinito allora potete fare, tra i tanti modi poco eleganti, una cosa come segue:
while true {
istruzioni da ripetere
}
oppure leggere il prossimo paragrafo
Anche while è una espressione ma emette come risultato un poco utile (). Il seguente esempio completa quanto finora detto:
Esempio 19.2
fn main() {
let mut x = 0;
let y = while x < 3 {
println!("ciao");
x = x + 1;
};
println!("{}", x);
println!("{:?}", y);
}
noterete come sempre il punto e virgola dopo la parentesi graffa perchè let è una assegnazione quindi uno statement. L'output: da cui ricaviamo:
| ciao ciao ciao 3 () |
Corredo interessante delle iterazioni, in generale, sono le istruzioni break e continue che, rispettivamente interrompono l'esecuzione del ciclo e saltano una iterazione. Vediamo un esempio con entrambe queste istruzioni di "rottura":
Esempio 19.3
fn main()
{
let mut x = 0;
while x < 10
{
x = x + 1;
if x == 2
{
continue;
}
println!("{}", x);
if x == 7
{
break;
}
}
}
da cui ricaviamo
| 1 3 4 5 6 7 |
Ovvero saltiamo il numero 2 come ci indica il primo if e successivamente saltiamo fuori dal while come ci dice il secondo if che introduce il break. Quest'ultimo non necessariamente interrompe il programma, in questo uscendo dal while ci ritroviamo al livello immediatamente superiore che in questo caso è il main il quale, non avendo altro da fare, termina.
Anche while è utilizzabile nel contesto while - let. Qui l'esempio, un classico, lo troverete quasi identico anche altrove, è un po' più complicato e sarà più chiaro quando avremo appreso altri concetti:
Esempio 19.4
fn main() {
let mut pila = vec![1, 2, 3, 4, 5];
while let Some(elemento) = pila.pop() {
println!("Elemento estratto: {}", elemento);
}
println!("Pila vuota: {:?}", pila);
}
ed ecco cosa ne risulta:
| Elemento estratto: 5 Elemento estratto: 4 Elemento estratto: 3 Elemento estratto: 2 Elemento estratto: 1 Pila vuota: [] |
-
pila.pop()restituisce unOption<i32>:Some(valore)se c'è un elemento,Nonequando la pila è vuota. -
while let Some(elemento) = pila.pop()continua il ciclo finché il patternSome(elemento)combacia, cioè finchépop()restituisceSome(...). -
Appena
pop()restituisceNone(pila vuota), il pattern non combacia più e il ciclo termina automaticamente.
Bisogna conosce il tipo Option (e anche Result, per il quale si può costruire un esempio simile) per comprendere appieno l'esempio ma la logica generale è che con questo costrutto possiamo ripetere un'azione finché un'espressione produce un certo pattern, senza dover scrivere manualmente un loop con match e break. Quindi non strettamente necessario ma molto utile e più leggero anche come manutenibilità.
Non è possibile usare while in congiunzione con i range (che rivedremo) ovvero non è possibile scrivere cose come:
while x in 1..10...
perchè il compilatore si arrabbia. Per ottenere lo stesso effetto dovrete ricorrere ad un codice un po' più verboso, ad esempio:
let mut i = 0;
while i < 5 {
println!("i = {}", i);
i += 1;
}