Clean Code in Rust: Prinzipien und Beispiele für Anfänger
\nRust ist eine leistungsstarke Systemprogrammiersprache, die für ihre Leistung und Speichersicherheit bekannt ist. Wie in jeder anderen Sprache ist das Schreiben von sauberem Code (Clean Code) jedoch eine entscheidende Fähigkeit. Sauberer Code ist leichter zu lesen, zu warten und zu erweitern. Für Anfänger in Rust hilft die Beherrschung der Clean-Code-Prinzipien von Anfang an, typische Fehler zu vermeiden und Ihren Code elegant und zuverlässig zu gestalten. In diesem Artikel werden wir die grundlegenden Prinzipien von sauberem Code in Rust anhand konkreter Beispiele erläutern.
\n\n1. Benennung von Variablen und Funktionen
\nEin guter Name sollte die Absicht des Programmierers erklären. In Rust ist es üblich, snake_case für Variablen, Funktionen und Module sowie CamelCase für Typen und Traits zu verwenden.
\n\nSchlechtes Beispiel:
\nfn c(a: i32, b: i32) -> i32 {\n let x = a + b;\n x\n}\n\nGutes Beispiel:
\nfn calculate_sum(first_number: i32, second_number: i32) -> i32 {\n let result = first_number + second_number;\n result\n}\nVerwenden Sie aussagekräftige Namen: user_name statt un, process_data statt pd. Vermeiden Sie Abkürzungen, es sei denn, sie sind allgemein üblich (z. B. idx für Index).
2. Kleine Funktionen und Einzelverantwortung
\nDas Prinzip der Einzelverantwortung (Single Responsibility Principle) besagt: Jede Funktion sollte nur eine Sache tun. Wenn eine Funktion mehrere Aktionen ausführt, ist sie schwer zu testen und zu ändern.
\n\nSchlechtes Beispiel (Funktion macht zu viel):
\nfn process_user(user_id: u32) {\n // Benutzer aus der Datenbank abrufen\n // Daten validieren\n // E-Mail senden\n // Loggen\n println!("Processing user {}", user_id);\n}\n\nGutes Beispiel (Aufteilung in kleine Funktionen):
\nfn get_user(user_id: u32) -> User {\n // Logik zum Abrufen des Benutzers\n User { id: user_id }\n}\n\nfn validate_user(user: &User) -> bool {\n // Validierungslogik\n user.id > 0\n}\n\nfn send_email(user: &User) {\n // Logik zum Senden der E-Mail\n println!("Email sent to user {}", user.id);\n}\n\nfn process_user(user_id: u32) {\n let user = get_user(user_id);\n if validate_user(&user) {\n send_email(&user);\n }\n}\nVersuchen Sie, dass eine Funktion in 10-20 Zeilen passt. Wenn sie länger ist, teilen Sie sie auf.
\n\n3. Fehlerbehandlung: Verwenden Sie Result und Option
\nRust fördert die explizite Fehlerbehandlung durch die Typen Result<T, E> und Option<T>. Vermeiden Sie die Verwendung von .unwrap() oder .expect() im Produktionscode – dies führt bei einem Fehler zu einer Panik.
Schlechtes Beispiel (gefährliches Extrahieren):
\nfn read_file(path: &str) -> String {\n let content = std::fs::read_to_string(path).unwrap(); // Kann abstürzen!\n content\n}\n\nGutes Beispiel (Fehlerbehandlung):
\nuse std::fs;\n\nfn read_file(path: &str) -> Result<String, std::io::Error> {\n let content = fs::read_to_string(path)?; // ?-Operator zum Weiterleiten des Fehlers\n Ok(content)\n}\n\nfn main() {\n match read_file("data.txt") {\n Ok(data) => println!("File content: {}", data),\n Err(e) => eprintln!("Error reading file: {}", e),\n }\n}\nVerwenden Sie den ?-Operator für Kürze, behandeln Sie Fehler jedoch immer auf der obersten Ebene. Für eigene Fehler erstellen Sie Aufzählungen mit dem Trait std::error::Error.
4. Kommentare und Dokumentation
\nSauberer Code sollte selbstdokumentierend sein. Kommentare erklären das Warum, nicht das Was. Verwenden Sie für die Dokumentation öffentlicher APIs /// (Doc-Kommentare).
Schlechtes Beispiel (nutzloser Kommentar):
\n// Zähler um 1 erhöhen\ncounter += 1;