Condizionali If in Rust
In Rust, l’istruzione if è una delle strutture di controllo più utilizzate. A differenza di molti altri linguaggi, in Rust if è un’espressione, il che significa che può restituire un valore. Inoltre, la condizione deve essere sempre di tipo bool: non esistono conversioni implicite da numeri o altri tipi.
If di base
La forma più semplice dell’if valuta una condizione booleana ed esegue un blocco di codice se questa è vera.
fn main() {
let temperatura = 30;
if temperatura > 25 {
println!("Fa caldo!");
}
}
A differenza di C o Java, le parentesi tonde attorno alla condizione non sono necessarie. Il compilatore emetterà un warning se le inserisci. La condizione deve sempre essere di tipo bool: scrivere if temperatura senza un confronto produrrebbe un errore di compilazione.
If-else
Con else possiamo definire un blocco alternativo da eseguire quando la condizione è falsa.
fn main() {
let eta = 16;
if eta >= 18 {
println!("Sei maggiorenne");
} else {
println!("Sei minorenne");
}
}
Catena if-else if-else
Per gestire più condizioni in sequenza, possiamo concatenare più rami con else if.
fn main() {
let voto = 85;
if voto >= 90 {
println!("Eccellente");
} else if voto >= 80 {
println!("Buono");
} else if voto >= 60 {
println!("Sufficiente");
} else {
println!("Insufficiente");
}
}
Rust valuta le condizioni dall’alto verso il basso e si ferma al primo ramo che risulta vero. Se nessuna condizione viene soddisfatta, viene eseguito il blocco else finale (se presente).
If come espressione
Una delle caratteristiche distintive di Rust è che if è un’espressione che restituisce un valore. Questo permette di assegnare il risultato di un if a una variabile.
fn main() {
let eta = 20;
let categoria = if eta >= 18 {
"adulto"
} else {
"minorenne"
};
println!("Categoria: {categoria}");
}
Quando si usa if come espressione, tutti i rami devono restituire lo stesso tipo. Non è possibile restituire un intero in un ramo e una stringa in un altro. Nota l’assenza del punto e virgola dopo le espressioni nei blocchi: l’ultimo valore senza ; diventa il valore restituito dal blocco.
fn main() {
let numero = 7;
let descrizione = if numero % 2 == 0 {
"pari"
} else {
"dispari"
};
println!("{numero} è {descrizione}");
}
Let-if binding
A partire dalla Rust Edition 2024, è possibile utilizzare let con if in modo ancora più espressivo. Il pattern classico consiste nell’assegnare con let il risultato di un’espressione if:
fn main() {
let punti = 75;
let livello = if punti >= 100 {
3
} else if punti >= 50 {
2
} else {
1
};
println!("Livello raggiunto: {livello}");
}
Questo pattern è preferibile rispetto alla dichiarazione mutabile seguita da riassegnamento nei vari rami, perché mantiene la variabile immutabile e rende il codice più chiaro.
If nidificati
È possibile annidare istruzioni if all’interno di altri blocchi if per gestire condizioni più complesse.
fn main() {
let eta = 25;
let ha_patente = true;
if eta >= 18 {
if ha_patente {
println!("Puoi guidare");
} else {
println!("Sei maggiorenne ma non hai la patente");
}
} else {
println!("Sei minorenne, non puoi guidare");
}
}
Tuttavia, in Rust è spesso preferibile usare gli operatori logici && e || per combinare le condizioni ed evitare nidificazioni eccessive:
fn main() {
let eta = 25;
let ha_patente = true;
if eta >= 18 && ha_patente {
println!("Puoi guidare");
} else {
println!("Non puoi guidare");
}
}
Differenze rispetto ad altri linguaggi
In Rust, la condizione dell’if deve essere un bool. Non è possibile scrivere codice come if 1 { ... } perche il compilatore segnalerà un errore di tipo. Questo comportamento previene una classe comune di bug presenti in linguaggi come C, dove qualsiasi valore diverso da zero viene considerato vero.
fn main() {
let valore = 1;
// Questo NON compila:
// if valore { println!("vero"); }
// Bisogna essere espliciti:
if valore != 0 {
println!("Il valore non è zero");
}
}
Conclusione
L’istruzione if in Rust è versatile e sicura. La sua natura di espressione permette di scrivere codice conciso e leggibile, mentre il requisito di condizioni strettamente booleane aiuta a prevenire errori comuni. Per condizioni con molti rami, considera anche l’uso dell’espressione match, che offre un pattern matching ancora più potente.