Funzioni in Rust
Una funzione è un blocco di codice riutilizzabile con un nome. Invece di riscrivere sempre gli stessi passaggi, li metti una volta in una funzione e la chiami ogni volta che ti serve. Ne stai già usando una: main.
Definire e chiamare una funzione
Sezione intitolata “Definire e chiamare una funzione”Definisci una funzione con fn e la chiami scrivendo il suo nome seguito da ():
fn greet() { println!("Ciao da una funzione!");}
fn main() { greet(); // la chiami greet(); // la chiami di nuovo}Output:
Ciao da una funzione!Ciao da una funzione!Parametri: dare un input alla funzione
Sezione intitolata “Parametri: dare un input alla funzione”Le funzioni diventano utili quando passi loro dei dati su cui lavorare. Questi input si chiamano parametri. In Rust devi scrivere il tipo di ogni parametro:
fn greet(name: &str) { println!("Ciao, {name}!");}
fn main() { greet("Alice"); greet("Bob");}Output:
Ciao, Alice!Ciao, Bob!Puoi avere tutti i parametri che vuoi, separati da virgole:
fn describe(name: &str, age: u32) { println!("{name} ha {age} anni");}
fn main() { describe("Ferris", 10);}Output:
Ferris ha 10 anniI valori che passi vengono abbinati ai parametri in base alla posizione: il primo valore va a name, il secondo ad age. Passarli nell’ordine sbagliato, come describe(10, "Ferris"), è un errore di compilazione, perché i tipi non corrispondono.
Restituire un valore
Sezione intitolata “Restituire un valore”Una funzione può restituire un valore a chi l’ha chiamata. Dichiari il tipo di ritorno dopo una freccia ->:
fn add(a: i32, b: i32) -> i32 { a + b}
fn main() { let sum = add(3, 4); println!("3 + 4 = {sum}");}Output:
3 + 4 = 7La regola del punto e virgola (importante!)
Sezione intitolata “La regola del punto e virgola (importante!)”Nota che a + b nell’esempio qui sopra non ha il punto e virgola. È un’idea chiave di Rust:
- Un’espressione senza punto e virgola è il valore che viene restituito.
- Aggiungere il punto e virgola la trasforma in un’istruzione che non restituisce niente.
Quindi questo non funziona:
fn add(a: i32, b: i32) -> i32 { a + b; // ❌ il punto e virgola significa «non restituire niente», ma abbiamo promesso un i32}Il compilatore si lamenterà che la funzione dovrebbe restituire un i32 ma non lo fa. Basta togliere il punto e virgola dall’ultima riga.
Mettiamo tutto insieme
Sezione intitolata “Mettiamo tutto insieme”fn square(n: i32) -> i32 { n * n}
fn main() { let result = square(5); println!("5 al quadrato fa {result}");}Output:
5 al quadrato fa 25Pratica
Sezione intitolata “Pratica”1. Da Celsius a Fahrenheit
Sezione intitolata “1. Da Celsius a Fahrenheit”Scrivi una funzione to_fahrenheit che riceve una temperatura in gradi Celsius come f64 e la restituisce in Fahrenheit. La formula è c * 9.0 / 5.0 + 32.0. Chiamala per 0, 100 e 37 gradi. Suggerimento: la firma è fn to_fahrenheit(c: f64) -> f64, e il corpo è una singola espressione senza punto e virgola.
Mostra la soluzione
fn to_fahrenheit(c: f64) -> f64 { c * 9.0 / 5.0 + 32.0}
fn main() { println!("0°C sono {}°F", to_fahrenheit(0.0)); println!("100°C sono {}°F", to_fahrenheit(100.0)); println!("37°C sono {}°F", to_fahrenheit(37.0));}Output:
0°C sono 32°F100°C sono 212°F37°C sono 98.6°FNota che passiamo 0.0, non 0. Il parametro è un f64, e Rust non trasforma di nascosto un intero in un numero decimale. Quando un f64 non ha parte decimale, {} lo stampa senza .0: per questo vedi 32 e non 32.0.
2. Il più grande di tre
Sezione intitolata “2. Il più grande di tre”Scrivi una funzione largest(a: i32, b: i32, c: i32) -> i32 che restituisce il più grande dei suoi tre numeri. Provala con (3, 9, 4) e (-2, -8, -5). Suggerimento: in Rust if è un’espressione (vedi If…else), quindi una catena if / else if / else può essere l’ultima riga della funzione.
Mostra la soluzione
fn largest(a: i32, b: i32, c: i32) -> i32 { if a >= b && a >= c { a } else if b >= c { b } else { c }}
fn main() { println!("{}", largest(3, 9, 4)); println!("{}", largest(-2, -8, -5));}Output:
9-2Nessuno dei rami finisce con il punto e virgola. Ognuno è un’espressione, l’intera catena di if restituisce uno di loro, e quello diventa il valore di ritorno. Usare >= invece di > garantisce che anche in caso di parità venga restituito un valore.
Riepilogo
Sezione intitolata “Riepilogo”- Definisci le funzioni con
fne le chiami connome(). - I parametri sono gli input; ognuno ha bisogno di un tipo:
fn greet(name: &str). - Dichiari un tipo di ritorno con
-> Tipo. - L’ultima espressione senza punto e virgola è il valore restituito.
- Anche
return valore;funziona, ma di solito si usa solo per uscire in anticipo.
Verifica veloce
Sezione intitolata “Verifica veloce”Verifica veloce
1. In Rust devi scrivere il tipo di ogni parametro di una funzione?
2. Come dichiari il tipo di ritorno di una funzione?
3. Perché a + b (senza punto e virgola) alla fine di una funzione diventa il suo valore di ritorno?
4. Conta se definisci una funzione sopra o sotto il punto in cui la chiami (per esempio sopra o sotto main)?
Punteggio: 0 / 4
Per approfondire
Sezione intitolata “Per approfondire”- Functions — The Rust Book (in inglese): il capitolo ufficiale su parametri, valori di ritorno e differenza tra istruzioni ed espressioni.
- Statements and Expressions — The Rust Book (in inglese): uno sguardo più da vicino all’idea dietro la regola del punto e virgola.
- Functions — Rust by Example (in inglese): esempi eseguibili, anche con
returnanticipato e funzioni che non restituiscono niente. - Functions — The Rust Reference (in inglese): le regole esatte su come si definiscono le funzioni, per quando vuoi i dettagli.
- La parola chiave
fn— documentazione della libreria standard (in inglese): un breve riassunto della sintassi delle funzioni, con esempi.