Eine der leistungsstärksten Funktionen von Rust ist das Pattern Matching, das durch das match-Schlüsselwort realisiert wird. Mit Rust 1.26 wurde der Begriff "Match Ergonomics" eingeführt - eine neue Logik zur Entpackung und automatischen Dereferenzierung von Referenzwerten innerhalb von Match-Ausdrücken, die darauf abzielt, die Anzahl der expliziten ref und * in Mustern zu reduzieren.
Vor der Einführung von Match Ergonomics musste man beim Arbeiten mit Enums, die Werte als Referenzen kapseln (z.B. Option<&T>), die Dereferenzierung im Muster ausdrücklich angeben:
let opt: Option<&i32> = Some(&10); match opt { Some(&val) => { /* ... */ }, None => {}, }
Das verringerte die Lesbarkeit und erhöhte die Wahrscheinlichkeit, sich bei den Dereferenzierungsebenen in komplexen Strukturen zu irren.
Mit der Einführung von Match Ergonomics dereferenziert Rust automatisch die Referenzen in Mustern, sodass der Code einfacher und natürlicher geschrieben werden kann:
let opt: Option<&i32> = Some(&10); match opt { Some(val) => println!("{}", val), None => (), }
Der Compiler "versteht", dass &i32 zu i32 dereferenziert werden muss, um den Programmierer zu unterstützen. Diese Funktion erleichtert die Arbeit mit den Typen Option, Result und deren Kombinationen mit Referenzen erheblich.
Hauptmerkmale:
* und ref in MusternWas ist der Unterschied zwischen der Verwendung von ref im Muster und dem Verweisen auf einen Wert (z.B. ref val vs &val)?
ref erstellt einen Verweis auf einen Wert, der sich auf dem Stack befindet, während &val mit einem bereits existierenden Verweis übereinstimmt. Dies ist wichtig, wenn man beispielsweise einen zusätzlichen Verweis für mutability benötigt.
Beispiel:
let x = 5; match x { ref r => println!("ref: {}", r), // r: &i32 }
Was passiert, wenn man bei Pattern Matching in Option<&T> einen mutablen Verweis nutzt?
Automatische Dereferenzierung funktioniert auch mit mutablen Verweisen. Wenn Sie Option<&mut T> haben, können Sie die mutable Variable direkt über match erhalten.
Beispiel:
let mut x = 5; let opt = Some(&mut x); match opt { Some(val) => *val += 1, None => {} }
Kann Match Ergonomics zu unerwarteten Borrowings oder Ownership-Fehlern führen?
Ja, wenn man sich nicht bewusst ist, dass innerhalb des Matches ein temporäres Borrow erstellt wird, das für den gesamten Matching-Zweig gilt und andere Operationen mit diesem Wert blockieren kann.
* und ref, während man die Match Ergonomics ignoriert, was die Kürze und Lesbarkeit des Codes verringert.Ein Neuling verwendet weiterhin den alten Stil Some(&val) oder Some(ref val), was zu Fehlern oder unvorhersehbarem Verhalten beim Aktualisieren von Rust auf eine neue Version führt.
Vorteile: Der Code funktioniert in früheren Rust-Versionen und ist für diejenigen, die vor der Einführung von Match Ergonomics gelernt haben, verständlich.
Nachteile: Geringe Ausdruckskraft, Risiko von Fehlern nach Compiler-Updates.
Ein Programmierer nutzt moderne Match Ergonomics, der Code ist kompakt und macht effektiv Gebrauch von automatischer Dereferenzierung.
Vorteile: Klarheit, gut lesbar, geringeres Risiko, sich bei den Verweisniveaus zu irren.
Nachteile: Dieser Code eignet sich nicht für ältere Rust-Versionen und kann bei denen, die wenig mit modernen Idiomen gearbeitet haben, zu Verwirrung führen.