Salta ai contenuti

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.

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!
▶ Provalo tu

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!
▶ Provalo tu

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 anni
▶ Provalo tu

I 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.

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 = 7
▶ Provalo tu

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.

fn square(n: i32) -> i32 {
n * n
}
fn main() {
let result = square(5);
println!("5 al quadrato fa {result}");
}

Output:

5 al quadrato fa 25
▶ Provalo tu

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°F
100°C sono 212°F
37°C sono 98.6°F
▶ Provalo tu

Nota 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.

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
-2
▶ Provalo tu

Nessuno 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.

  • Definisci le funzioni con fn e le chiami con nome().
  • 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

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