Warum Code Review auf Rust mehr ist als nur Klammern zu prüfen
Rust ist eine Sprache, die sichere Speicherverwaltung und hohe Leistung verspricht. Aber selbst der strengste Compiler schützt nicht vor logischen Fehlern, unidiomatischem Code oder ungerechtfertigter Verwendung von unsafe. Code Review auf Rust ist eine Kunst. Sie schauen nicht nur, ob die geschweiften Klammern geschlossen sind. Sie prüfen, wie der Entwickler die Einschränkungen des Borrow Checkers umgangen (oder nicht umgangen) hat, wie effizient er Iteratoren einsetzt und ob er versucht, das System mit rohen Zeigern zu „überlisten".
In diesem Artikel erkläre ich, auf welche Aspekte Sie bei einem Code Review in Rust achten sollten. Ohne überflüssige Theorie – nur praktische Tipps, Beispiele und eine Checkliste, die Sie an die Wand hängen (oder in den Lesezeichen speichern) können. Los geht's!
1. Ownership, Borrowing und Lebenszeiten: Die Hauptschmerzquelle
Das Erste, was Sie prüfen müssen, ist, ob das Ownership-System korrekt funktioniert. Auch wenn der Code kompiliert, heißt das nicht, dass er korrekt ist. Typische Probleme:
- Übermäßiges Klonen. Wenn eine Referenz ausgereicht hätte, kopiert der Entwickler die Daten. Das tötet die Leistung.
- Ausleihen von mutable und immutable. Wenn es im selben Gültigkeitsbereich gleichzeitig
&mut Tund&Tgibt – das führt zu einem Fehler. Manchmal kann man den Code jedoch umordnen, um dies zu vermeiden. - Falsche Lebenszeiten (Lifetimes). Besonders in komplexen Strukturen mit mehreren Referenzen.
Beispiel: Schlechter Code
fn process(data: &Vec<i32>) -> i32 { let mut sum = 0; for &x in data.iter() { sum += x; } // Alles okay, aber warum &Vec übergeben, wenn &[i32] reicht? sum}Guter Code
fn process(data: &[i32]) -> i32 { data.iter().sum()}Was beim Review prüfen: Wird &Vec, &String oder &HashMap übergeben, wo ein Slice ausreicht? Werden clone() unnötig verwendet? Sind die Lebenszeit-Annotationen korrekt gesetzt?
2. Unsafe: Die rote Zone
unsafe-Blöcke sind wie eine offene Luke im sicheren Rust. Sie müssen gerechtfertigt, minimal und sorgfältig dokumentiert sein. Achten Sie beim Code Review auf:
- Warum wird unsafe verwendet? Oft kommt man mit sicheren Abstraktionen aus.
- Korrektheit roher Zeiger. Wird ein Nullzeiger dereferenziert? Hängt eine Referenz nach der Speicherfreigabe?
- Invarianten. Code mit
unsafesollte explizit beschreiben, welche Invarianten er aufrechterhält.
Beispiel: Gefährliches unsafe
unsafe fn dangerous() { let ptr = 0x12345 as *mut i32; *ptr = 42; // Was ist, wenn an dieser Adresse nichts ist?}Solcher Code sollte das Review nicht bestehen. Auch wenn „es funktioniert" – das ist kein Argument.
Gutes unsafe
unsafe fn init_buffer(buf: &mut [u8]) { // Wir sind sicher, dass buf auf gültigen Speicher zeigt, // da die aufrufende Seite dies garantiert. std::ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len());}Was prüfen: Gibt es einen Kommentar mit Begründung für jedes unsafe? Gibt es Tests, die Grenzfälle prüfen? Werden die Sicherheitsgarantien verletzt?
3. Closures und funktionaler Stil
Rust fördert einen funktionalen Ansatz: Iteratoren, Closures, map, filter, fold. Dies kann jedoch zu übermäßiger Komplexität führen. Achten Sie beim Review auf:
- Werden Closures übermäßig genutzt? Wenn eine Closure viele Variablen einfängt, sollte die Logik vielleicht in eine separate Funktion ausgelagert werden.