Le funzioni sono una parte essenziale di qualsiasi linguaggio di programmazione, e Rust non fa eccezione. Permettono di suddividere il codice in unità logiche, migliorandone la leggibilità e la riusabilità. Inoltre, Rust offre strumenti avanzati come i moduli per organizzare grandi progetti e una gestione chiara dello scope per controllare la visibilità delle variabili e delle funzioni. In questo articolo, esploreremo come definire e usare funzioni, gestire parametri e valori di ritorno, comprendere lo scope e strutturare il codice con i moduli.
In Rust, le funzioni si definiscono usando la parola chiave fn
, seguita dal nome della funzione, una lista di parametri opzionali racchiusi tra parentesi tonde, e un corpo racchiuso tra parentesi graffe.
fn saluta() {
println!("Ciao, benvenuto in Rust!");
}
fn main() {
saluta(); // Chiamata della funzione
}
In questo esempio, abbiamo definito una funzione semplice chiamata saluta
e l’abbiamo richiamata all’interno della funzione principale main
.
Le funzioni possono accettare parametri per rendere il loro comportamento più flessibile. Ogni parametro deve essere accompagnato dal tipo.
fn saluta_persona(nome: &str) {
println!("Ciao, {}!", nome);
}
fn main() {
saluta_persona("Alice");
}
Le funzioni possono restituire valori utilizzando il tipo di ritorno, specificato dopo una freccia ->
.
fn somma(a: i32, b: i32) -> i32 {
a + b // L'ultima espressione è il valore restituito
}
fn main() {
let risultato = somma(4, 6);
println!("La somma è: {}", risultato);
}
Se non ci sono valori da restituire, il tipo di ritorno è ()
(unit), che può essere omesso.
Ecco una funzione con parametri e un valore di ritorno, utilizzata per calcolare l’area di un rettangolo:
fn calcola_area(lunghezza: f32, larghezza: f32) -> f32 {
lunghezza * larghezza
}
fn main() {
let area = calcola_area(5.0, 3.0);
println!("L'area del rettangolo è: {}", area);
}
In Rust, lo scope (ambito) di una variabile o funzione definisce dove può essere usata nel codice. Comprendere come funziona lo scope è essenziale per scrivere codice sicuro e ben organizzato.
Le variabili in Rust sono visibili solo all’interno del blocco in cui vengono dichiarate. Ad esempio:
fn main() {
let x = 10;
{
let y = 5; // y è visibile solo all'interno di questo blocco
println!("x: {}, y: {}", x, y);
}
// println!("y: {}", y); // Errore: y non è visibile qui
}
Quando una variabile esce dallo scope, la sua memoria viene liberata automaticamente grazie al sistema di ownership di Rust.
Le funzioni possono accedere solo alle variabili che vengono passate come argomenti o dichiarate all’interno dello scope della funzione stessa.
fn stampa_valore(valore: i32) {
println!("Il valore è: {}", valore);
}
fn main() {
let numero = 42;
stampa_valore(numero);
}
Man mano che il tuo progetto cresce, avrai bisogno di organizzare il codice. I moduli in Rust ti aiutano a strutturare le tue funzioni e altre definizioni in unità logiche.
Un modulo è una raccolta di funzioni e altri oggetti correlati.
mod calcoli {
pub fn somma(a: i32, b: i32) -> i32 {
a + b
}
}
fn main() {
let risultato = calcoli::somma(10, 20);
println!("La somma è: {}", risultato);
}
pub
rende la funzione accessibile dall’esterno del modulo.pub
sono private al modulo.Per progetti più grandi, puoi separare i moduli in file diversi:
File main.rs
:
mod calcoli;
fn main() {
let risultato = calcoli::somma(10, 5);
println!("Risultato: {}", risultato);
}
calcoli.rs
:pub fn somma(a: i32, b: i32) -> i32 {
a + b
}
moltiplica
che accetta due numeri e restituisce il prodotto.somma
, sottrai
) in un modulo chiamato operazioni
.Le funzioni e i moduli in Rust sono strumenti potenti per creare codice leggibile, riutilizzabile e ben strutturato. Apprendere i concetti di scope e modularità ti permette di scrivere programmi ben organizzati e facilmente scalabili. Nella prossima lezione, esploreremo concetti come Ownership, Borrowing e Lifetimes, che aggiungono ancora più flessibilità al tuo codice.