0Pricing
Learn Rust Coding · Lezione

Funzioni generiche

Parametrizzi il comportamento in base al tipo.

Funzioni generiche è una lezione Learn Rust Coding gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Learn Rust Coding, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Learn Rust Coding include 4 lezioni in totale.

Perché usare funzioni generiche

Le funzioni generiche permettono di scrivere una sola funzione compatibile con molti tipi, invece di duplicare il codice per ogni tipo. Rust sostituisce il tipo segnaposto durante la compilazione.

Immagini di scrivere un largest per gli interi e un altro per i caratteri. I generics riuniscono queste due funzioni in un'unica definizione, senza costi a runtime.

Parametri di tipo

Una funzione generica dichiara un parametro di tipo tra parentesi angolari dopo il nome. Il nome T è una convenzione, ma può essere usato qualsiasi identificatore in CamelCase.

Il parametro può quindi comparire negli argomenti e nel tipo restituito, rappresentando il tipo concreto scelto dal chiamante.

fn first<T>(pair: (T, T)) -> T {
    pair.0
}

Una semplice funzione identità

Questo programma definisce un echo generico che restituisce invariato il proprio argomento. Viene chiamato una volta con un intero e una volta con una string slice.

Il compilatore genera una versione concreta separata per ogni tipo effettivamente utilizzato.

fn echo<T>(value: T) -> T {
    value
}

fn main() {
    println!("{}", echo(42));
    println!("{}", echo("hi"));
}

Monomorfizzazione

Rust usa la monomorfizzazione: durante la compilazione produce una copia specializzata della funzione per ogni tipo concreto utilizzato. Non sono necessari boxing o dispatch virtuale.

Il risultato è codice generico che viene eseguito con la stessa velocità del codice specifico per tipo scritto manualmente.

I generics richiedono vincoli

All'interno di una funzione generica può usare solo le operazioni supportate da ogni possibile tipo. Un semplice T non può essere sommato, confrontato o stampato.

Questo codice non viene compilato perché T potrebbe non implementare il confronto. Lo correggeremo applicando un trait bound.

fn larger<T>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

Aggiunta di un trait bound

Per confrontare i valori, vincoliamo T con PartialOrd. Il vincolo garantisce che il tipo supporti l'operatore >.

Aggiungiamo anche Copy, così i valori possono essere restituiti senza problemi di spostamento per tipi semplici come gli interi.

fn larger<T: PartialOrd + Copy>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

Chiamata della funzione vincolata

Ora la funzione funziona per qualsiasi tipo che implementi entrambi i trait. Sia gli interi sia i numeri in virgola mobile soddisfano PartialOrd + Copy.

Lo stesso codice sorgente, monomorfizzato in due versioni, stampa i risultati di ogni chiamata.

fn larger<T: PartialOrd + Copy>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

fn main() {
    println!("{}", larger(3, 9));
    println!("{}", larger(2.5, 1.0));
}

Più parametri di tipo

Una funzione può dichiarare diversi parametri di tipo. Ognuno è indipendente, quindi i due argomenti possono avere tipi diversi.

Qui pair accetta un qualsiasi T e un qualsiasi U e li restituisce come tupla.

fn pair<T, U>(a: T, b: U) -> (T, U) {
    (a, b)
}

Stampa di valori generici

Per stampare un valore generico con {}, il tipo deve implementare Display. Aggiungiamo questo vincolo, così è possibile passare qualsiasi tipo stampabile.

Questo esempio assegna un'etichetta a un valore e lo restituisce, mostrando un vincolo usato esclusivamente per la formattazione.

use std::fmt::Display;

fn announce<T: Display>(label: &str, value: T) {
    println!("{}: {}", label, value);
}

fn main() {
    announce("count", 7);
    announce("name", "Ada");
}

Sintassi turbofish

A volte il compilatore non riesce a dedurre T dai soli argomenti. Il turbofish ::<Type> permette di specificarlo esplicitamente nel punto della chiamata.

È usato soprattutto con metodi come parse e collect, quando il tipo restituito è ambiguo.

fn main() {
    let n = "42".parse::<i32>().unwrap();
    println!("{}", n + 1);
}

Generics sui riferimenti

I parametri generici funzionano anche con i riferimenti. Applicare il vincolo per riferimento evita di richiedere Copy quando è sufficiente leggere i valori.

Questo helper in stile longest_str prende in prestito due slice e ne restituisce una senza acquisirne la proprietà.

fn pick<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> &'a T {
    if a > b { a } else { b }
}

Verifica rapida

Verifichi la sua comprensione delle funzioni generiche in Rust.

Riepilogo

Le funzioni generiche usano parametri di tipo tra parentesi angolari per lavorare con molti tipi, senza costi a runtime grazie alla monomorfizzazione.

Le operazioni su un tipo generico richiedono trait bound come PartialOrd, Copy o Display. Usi il turbofish quando l'inferenza non riesce a determinare il tipo.

Domande Frequenti

La lezione «Funzioni generiche» è gratuita?

Sì — il testo completo di «Funzioni generiche» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Learn Rust Coding, passa a CoddyKit PRO. Il corso Learn Rust Coding include 4 lezioni in totale.

Cosa imparerò in «Funzioni generiche»?

Parametrizzi il comportamento in base al tipo. Eserciti Learn Rust Coding con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Learn Rust Coding?

Non è richiesta alcuna esperienza precedente. Learn Rust Coding su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.

Quanto tempo richiede la lezione «Funzioni generiche»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Learn Rust Coding?

Sì. Ogni lezione Learn Rust Coding include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Funzioni generiche
  2. Struct ed enum generici
  3. Vincoli dei trait
  4. Clausole where e vincoli multipli
← Torna a Learn Rust Coding