saverioriotto.it

Funzioni in Rust: Scrivi Codice Ordinato e Riutilizzabile

Impara a usare le funzioni in Rust per creare codice ordinato e riutilizzabile. Scopri come gestire parametri, valori di ritorno, scope e organizzare il codice con i moduli.

Funzioni in Rust: Scrivi Codice Ordinato e Riutilizzabile

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.

Definizione e Uso delle Funzioni

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.

Esempio: Funzione Base

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.

Parametri e Valori di Ritorno

Parametri

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");
}

Valori di Ritorno

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.

Esempio Completo

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);
}

Scope in Rust

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.

Scope delle Variabili

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.

Scope e Funzioni

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);
}

Creare Moduli per Organizzare il Codice

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.

Definizione di un Modulo

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);
}
  • La parola chiave pub rende la funzione accessibile dall’esterno del modulo.
  • Le funzioni senza pub sono private al modulo.

Moduli in File Separati

Per progetti più grandi, puoi separare i moduli in file diversi:

  1. File main.rs:

    mod calcoli;
    
    fn main() {
        let risultato = calcoli::somma(10, 5);
        println!("Risultato: {}", risultato);
    }
  2. File calcoli.rs:
    pub fn somma(a: i32, b: i32) -> i32 {
        a + b
    }

Esercizi Pratici

  1. Esercizio 1: Crea una funzione chiamata moltiplica che accetta due numeri e restituisce il prodotto.
  2. Esercizio 2: Organizza due funzioni (somma, sottrai) in un modulo chiamato operazioni.
  3. Esercizio 3: Scrivi un programma che utilizza una funzione in un modulo separato per calcolare l’area di un cerchio.
  4. Esercizio 4: Prova a creare una variabile all’interno di un blocco e vedere come cambia la visibilità usando lo scope.

Conclusione

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.




Commenti
* Obbligatorio