Vai al contenuto
eLearner.app
Modulo 5 · Lezione 1 di 29/14 nel corso~12 min
Lezioni del modulo (1/2)

Generici e funzioni

I generics (tipi generici) consentono di scrivere codice flessibile e riutilizzabile, evitando la duplicazione di logica per tipi di dati differenti. Invece di definire più funzioni o strutture per tipi diversi (come i32, f64, o String), possiamo usare un parametro di tipo generico, convenzionalmente indicato con la lettera T.

Il compilatore Rust gestisce i generics tramite un processo chiamato monomorfizzazione: durante la compilazione, il compilatore genera una copia del codice generico per ciascun tipo concreto con cui viene effettivamente utilizzato. In questo modo non c'è alcun sovraccarico di prestazioni a runtime.


Funzioni Generiche

Per definire una funzione generica, inseriamo il parametro di tipo <T> subito dopo il nome della funzione e prima dell'elenco dei parametri:

Code
fn print_value<T: std::fmt::Debug>(value: T) {
    println!("Valore: {:?}", value);
}

Nelle funzioni generiche, possiamo usare il tipo generico T sia per i tipi degli argomenti che per il tipo di ritorno:

Code
fn identity<T>(value: T) -> T {
    value
}

Strutture Generiche

Possiamo utilizzare i parametri di tipo generico anche all'interno delle strutture dati (struct) per definire campi flessibili:

Code
struct KeyValuePair<K, V> {
    key: K,
    value: V,
}

fn main() {
    let pair = KeyValuePair {
        key: String::from("eta"),
        value: 30,
    };
}

Nel blocco impl per una struct generica, dobbiamo dichiarare il parametro di tipo <T> subito dopo la parola chiave impl per indicare che stiamo implementando metodi su una struttura generica:

Code
struct Container<T> {
    value: T,
}

impl<T> Container<T> {
    fn new(value: T) -> Self {
        Container { value }
    }

    fn value(&self) -> &T {
        &self.value
    }
}

Prova tu

Esercizio 1: La struttura Point

Esercizio#rust.m5.l1.e1
Tentativi: 0Caricamento…

Definisci una struttura generica chiamata Point<T> con due campi: x di tipo T e y di tipo T. Nel main, istanzia una variabile point contenente un Point con valori x pari a 5 e y pari a 10 (interi), quindi stampa a schermo il valore di point.x.

Caricamento editor…
Mostra suggerimento

Dichiara la struct usando `struct Point<T> { x: T, y: T }`. Istanziala nel main e usa `point.x` per stamparla.

Soluzione disponibile dopo 3 tentativi

Esercizio 2: Inversione di una Tupla con swap

Esercizio#rust.m5.l1.e2
Tentativi: 0Caricamento…

Scrivi una funzione generica chiamata swap<T> che accetta in input una tupla di due elementi (T, T) e restituisce una nuova tupla (T, T) con gli elementi invertiti di posizione. Nel main, chiama la funzione con la tupla (1, 2) e stampa il risultato.

Caricamento editor…
Mostra suggerimento

La firma della funzione deve essere `fn swap<T>(pair: (T, T)) -> (T, T)`. Restituisci la tupla invertita con `(pair.1, pair.0)`.

Soluzione disponibile dopo 3 tentativi

Esercizio 3: La struttura Container

Esercizio#rust.m5.l1.e3
Tentativi: 0Caricamento…

Definisci una struct generica Container<T> contenente un campo value di tipo T. Implementa un blocco impl generico per definire un metodo new che accetta un valore di tipo T e restituisce un'istanza di Container<T>.

Caricamento editor…
Mostra suggerimento

Usa `impl<T> Container<T>`per implementare il metodo associato`fn new(value: T) -> Self { Container { value } }`.

Soluzione disponibile dopo 3 tentativi