Rust-Code-Review: 5 Anmerkungen, die jeder Senior macht

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 Rust so streng ist und wie Code-Review hilft, nicht verrückt zu werden

\n

Sie haben Rust-Code geschrieben. Er wurde kompiliert – hurra! Aber das Problem: Der Senior-Entwickler seufzt, wenn er Ihren Pull Request öffnet, und beginnt, Kommentare zu schreiben. Kommt Ihnen das bekannt vor? Rust ist eine Sprache mit einer einzigartigen Philosophie: Sie vertraut Ihnen, überprüft aber alles. Allerdings sieht der Compiler nicht, was ein erfahrenes Auge sieht. Er wird nicht sagen: „Hey, das kann man eleganter machen“ oder „Ihr Code leckt – nicht Speicher, sondern Performance“.

\n

In diesem Artikel führen wir ein Rust-Code-Review durch und analysieren typische Anmerkungen von Seniors. Sie erfahren, wie Sie „einfach funktionierenden Code“ in idiomatischen und zuverlässigen Code verwandeln. Los geht's!

\n\n

1. Ignorieren des Typsystems: „Ach, ich packe einfach alles in String“

\n

Der häufigste Fehler von Anfängern ist die Verwendung von String oder generischen Typen, wo konkrete Typen benötigt werden. Ein Senior wird sagen: „Ihr Typ sollte die Geschäftslogik widerspiegeln, nicht einfach ein String sein“.

\n

Problem: Verlust der Semantik

\n

Stellen Sie sich vor, Sie schreiben eine Funktion für die Arbeit mit E-Mail-Adressen:

\n
fn send_email(to: String, subject: String, body: String) {\n    // ...\n}
\n

Was ist hier falsch? Sie könnten to und subject verwechseln – der Compiler wird es nicht bemerken. Ein Senior würde das Newtype-Pattern vorschlagen:

\n
struct Email(String);\nstruct Subject(String);\nstruct Body(String);\n\nfn send_email(to: Email, subject: Subject, body: Body) {\n    // ...\n}
\n

Scheint das überflüssig? Bei einem Rust-Code-Review ist dieser Ansatz der Goldstandard. Er macht den Code selbstdokumentierend und schließt eine ganze Klasse von Fehlern aus.

\n\n

2. Übermäßiger Gebrauch von clone(): Kopieren bedeutet nicht Besitzen

\n

Junior-Entwickler verwenden oft .clone() überall dort, wo der Compiler sich über Ausleihen beschwert. Ein Senior wird sagen: „Du gibst einfach vor dem Borrow Checker auf. Denk anders“.

\n

Beispiel: Überflüssiges Clone

\n
fn process(data: Vec<i32>) {\n    let first = data[0].clone();\n    let second = data[1].clone();\n    // ...\n}
\n

i32 implementiert das Copy-Trait – clone() ist hier völlig überflüssig. Aber das Problem geht tiefer: Wenn Sie große Strukturen (z. B. Vec oder String) klonen, erhalten Sie einen Performance-Einbruch.

\n

Der richtige Ansatz ist die Arbeit mit Referenzen:

\n
fn process(data: &[i32]) {\n    let first = &data[0];\n    let second = &data[1];\n    // ...\n}
\n

Bei einem Rust-Code-Review müssen Sie erklären, warum Sie klonen. Wenn die Antwort „damit der Compiler nicht meckert“ lautet – bereiten Sie sich auf einen vernichtenden Kommentar vor.

\n\n

3. Schlechte Fehlerbehandlung: .unwrap() ist keine endgültige Lösung

\n

Seniors hassen unwrap() und expect() im Production-Code. Warum? Weil sie einen potenziell behebbaren Fehler in eine Panik verwandeln. Und eine Panik in Rust bedeutet einen Programmabsturz.

\n

Was ist falsch an diesem Code?

\n
let file_content = std::fs::read_to_string("config.txt").unwrap();
\n

Wenn die Datei nicht existiert – stürzt das Programm ab. Ein Senior würde vorschlagen:

\n
let file_content = std::fs::read_to_string("config.txt")\n    .map_err(|e| format!("Failed to read config: {}", e))?;
\n

Verwenden Sie den ?-Operator und eigene Fehlertypen. Das ist die Grundlage von idiomatischem Rust. Bei einem Rust-Code-Review ist dies eine der ersten Anmerkungen.

\n\n

4. Vergessene Performance: Allokationen und Iteratoren

\n

Rust ist eine Systemsprache. Ein Senior wird nicht nur auf Sicherheit, sondern auch auf Geschwindigkeit achten. Ein typisches Problem ist die Erstellung überflüssiger Collections.

\n

Beispiel: Unnötiges Sammeln

\n
let numbers: Vec<i32> = (0..100).collect();\nlet doubled: Vec<i32> = numbers.iter().map(|x| x * 2).collect();                

Blogs

Buchempfehlungen