Sauberer Code in Rust: Prinzipien, Redewendungen und praktische Beispiele

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Warum Sauberer Code in Rust Nicht Nur Stil ist



Rust ist eine Sprache, die die Leistung von C++ mit Speichersicherheit kombiniert, aber ihr einzigartiges Ownership- und Borrowing-System erfordert einen speziellen Ansatz beim Schreiben von Code. Die von Robert Martin formulierten Clean-Code-Prinzipien erhalten in Rust eine neue Dimension: Hier ist die Sauberkeit des Codes direkt mit Korrektheit, Leistung und Wartbarkeit verbunden.



In diesem Artikel werden wir untersuchen, wie man Rust-Idiome anwendet, um selbstdokumentierenden, sicheren und effizienten Code zu erstellen. Sie werden sehen, wie man typische Anfängerfehler durch elegante, in der Rust-Community akzeptierte Lösungen ersetzt.



1. Idiomatische Fehlerbehandlung: Von unwrap() zu Ausdrucksstarken Mustern



Eines der ersten Probleme, auf die Anfänger stoßen, ist die übermäßige Verwendung von unwrap(). Im Clean Code ist ein Fehler keine Ausnahme, sondern ein Teil der Architektur. Rust bietet leistungsstarke Option- und Result-Typen für die explizite Behandlung von Grenzfällen.



Schlechtes Beispiel (Unsauberer Code)

fn parse_number(input: &str) -> i32 {    input.parse::<i32>().unwrap()}

fn main() { let val = parse_number("not a number"); println!("{}", val); // Panik!}


Gutes Beispiel (Sauberer Code)

use std::num::ParseIntError;

fn parse_number(input: &str) -> Result<i32, ParseIntError> { input.parse::<i32>()}

fn main() { match parse_number("42") { Ok(n) => println!("Zahl: {}", n), Err(e) => eprintln!("Fehler: {}", e), }}


Warum ist das Sauberer Code? Die Funktion gibt explizit an, dass sie fehlschlagen kann. Der aufrufende Code entscheidet, wie mit dem Fehler umgegangen wird — protokollieren, wiederholen oder den Fehler nach oben weiterleiten.



Fortgeschrittene Technik: Der ?-Operator

fn read_config(path: &str) -> Result<String, std::io::Error> {    let content = std::fs::read_to_string(path)?;    Ok(content)}


Der ?-Operator ist ein eleganter Ersatz für ausführliche match-Ausdrücke. Er gibt den Fehler nach oben zurück, wenn das Ergebnis Err ist, und extrahiert den Wert, wenn es Ok ist. Dies reduziert Verschachtelungen und verbessert die Lesbarkeit.



2. Ownership und Borrowing: Gestalten Sie die Architektur, Kämpfen Sie Nicht Gegen den Compiler



Das Ownership-System von Rust mag wie eine Einschränkung erscheinen, hilft aber tatsächlich dabei, sauberen Code zu schreiben. Probleme beginnen, wenn ein Entwickler versucht, den Compiler unnötigerweise mit clone() oder Rc<RefCell> zu "überlisten".



Anti-Pattern: Übermäßiges Klonen

fn process_data(data: Vec<String>) {    for item in data.clone() { // Warum klonen?        println!("{}", item);    }    // data wird nicht mehr verwendet}


Saubere Lösung: Borrowing per Referenz

fn process_data(data: &[String]) {    for item in data {        println!("{}", item);    }}

fn main() { let my_data = vec!["a".to_string(), "b".to_string()]; process_data(&my_data); // Ownership bleibt bei main println!("Vektor ist immer noch zugänglich: {:?}", my_data);}


Clean-Code-Prinzip: Minimaler Gültigkeitsbereich für Mutationen. Wenn eine Funktion Daten nicht ändern soll — akzeptieren Sie eine unveränderliche Referenz &T. Wenn eine Änderung erforderlich ist — &mut T. Dies macht den Code vorhersagbar und sicher.



Idiom: Übergabe von Ownership zur Transformation

fn to_uppercase(mut text: String) -> String {    text.make_ascii_uppercase();    text // Ownership wird zurückgegeben}


Hier "verbraucht" die Funktion den String, ändert ihn und gibt ihn zurück. Dies ist effizient (kein Kopieren) und explizit: Der Aufrufer versteht, dass die ursprüngliche Variable nicht mehr gültig ist.



3. Closures und Funktionale

Blogs

Buchempfehlungen