Una delle funzionalità più potenti di Rust è il pattern matching, realizzato attraverso il comando match. Con l'uscita di Rust 1.26 è emerso il termine "match ergonomics" — una nuova logica di disimballaggio e autodereferenziazione dei valori referenziali all'interno delle espressioni di matching, progettata per ridurre il numero di espliciti ref e * nei pattern.
Prima dell'arrivo del match ergonomics, quando si usava un enum che incapsulava un valore in un riferimento (ad esempio, Option<&T>), si doveva specificare esplicitamente la dereferenziazione del pattern:
let opt: Option<&i32> = Some(&10); match opt { Some(&val) => { /* ... */ }, None => {}, }
Questo riduceva la leggibilità e aumentava la probabilità di errore con i livelli di dereferenziazione in strutture complesse.
Con l'introduzione del match ergonomics, Rust dereferenzia automaticamente i riferimenti nei pattern, permettendo di scrivere codice più semplice e naturale:
let opt: Option<&i32> = Some(&10); match opt { Some(val) => println!("{}", val), None => (), }
Il compilatore "capisce" che deve dereferenziare &i32 in i32 per comodità del programmatore. Questa funzione facilita notevolmente il lavoro con i tipi Option, Result e le loro combinazioni con riferimenti.
Caratteristiche chiave:
* e ref nei patternQual è la differenza tra l'uso di ref nel pattern e un riferimento a un valore (ad esempio, ref val vs &val)?
ref crea un riferimento a un valore situato nello stack, mentre &val corrisponde a un riferimento già esistente. Questo è importante, ad esempio, se hai bisogno di un riferimento aggiuntivo per lavorare con la mutabilità.
Esempio:
let x = 5; match x { ref r => println!("ref: {}", r), // r: &i32 }
Cosa succede se durante il pattern matching in Option<&T> si utilizza un riferimento mutabile?
L'autodereferenziazione funziona anche con i riferimenti mutabili. Se hai Option<&mut T>, puoi ottenere direttamente una variabile mutabile tramite match.
Esempio:
let mut x = 5; let opt = Some(&mut x); match opt { Some(val) => *val += 1, None => {} }
Il match ergonomics può portare a prestiti non evidenti o errori di possesso?
Può, se non si è consapevoli che all'interno del match viene creato un prestito temporaneo (borrow), che agisce su tutto il ramo del matching e può bloccare altre operazioni su quel valore.
* e ref, ignorando il match ergonomics, cosa che riduce la concisione e la leggibilità del codiceUn principiante continua a utilizzare il vecchio stile Some(&val) o Some(ref val), ricevendo errori o comportamenti imprevedibili durante l'aggiornamento di Rust alla nuova versione
Pro: Il codice funziona su versioni precedenti di Rust ed è comprensibile da chi ha studiato prima dell'introduzione del match ergonomics
Contro: Bassa espressività, rischio di errori dopo gli aggiornamenti del compilatore
Un programmatore utilizza il moderno match ergonomics, il codice è compatto ed efficace nell'utilizzare l'autodereferenziazione
Pro: Concisione, è facilmente leggibile, minore rischio di errori con i livelli di riferimenti
Contro: Per le versioni più vecchie di Rust, tale codice non sarà adatto e potrebbe generare incomprensione in coloro che hanno poca esperienza con l'idiosincrasia moderna