Debugging von Rust-Code: Vollständiger Leitfaden zu Techniken und Werkzeugen

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

Debugging von Rust-Code: von «println!» bis zu Profi-Werkzeugen



Jeder, der mindestens eine Woche Rust geschrieben hat, kennt dieses Gefühl: Der Compiler hat durchgelassen, das Programm wurde kompiliert, startet … und macht etwas völlig Unerwartetes. Oder stürzt einfach mit einem rätselhaften Segmentation fault ab. Willkommen in der Welt des Debuggings! Die gute Nachricht: Rust bietet dafür ein ganzes Arsenal – vom einfachen Makro bis zu fortgeschrittenen Debuggern. In diesem Artikel besprechen wir alle Methoden des Debugging von Rust-Code, von den grundlegenden bis zu den professionellen.



1. Das Grundlagen-Set: Die Makros dbg! und eprintln!



Beginnen wir mit dem Einfachsten und Zugänglichsten. Wenn Sie Rust-Code schreiben und schnell verstehen möchten, was in Variablen passiert – verwenden Sie dbg!. Es gibt sowohl den Variablennamen als auch seinen Wert sowie die Datei und Zeile aus. Viel bequemer als das gute alte println!.



fn calculate_even_sum(numbers: &[i32]) -> i32 {    let mut sum = 0;    for &n in numbers {        if n % 2 == 0 {            sum += n;            dbg!(n, sum);  // sehen wir uns jede gerade Zahl und die aktuelle Summe an        }    }    sum}

fn main() { let data = vec![1, 2, 3, 4, 5, 6]; let result = calculate_even_sum(&data); dbg!(result);}


Starten Sie es – und Sie werden so etwas sehen:



[src/main.rs:6:13] n = 2[src/main.rs:6:13] sum = 2[src/main.rs:6:13] n = 4[src/main.rs:6:13] sum = 6[src/main.rs:6:13] n = 6[src/main.rs:6:13] sum = 12[src/main.rs:12:5] result = 12


Und wenn Sie in stderr schreiben müssen (z. B. um stdout bei Pipes nicht zu stören) – verwenden Sie eprintln!. Dies ist unverzichtbar beim Debugging von Rust-Code in einer Produktionsumgebung.



2. Fortgeschrittenes Logging mit log und env_logger



Wenn das Projekt wächst, wird es mühsam, überall dbg! zu verteilen. Hier helfen die Crates log und env_logger. Sie ermöglichen es, Logs ohne Neukompilierung ein- und auszuschalten.



use log::{info, warn, error, debug};

fn main() { env_logger::init();

info!("Programm gestartet"); let x = 42; debug!("Wert von x: {}", x);

if x > 100 { warn!("x ist zu groß!"); } else { error!("Das ist kein Fehler, nur ein Test"); }}


Starten Sie mit der Umgebungsvariable RUST_LOG=debug cargo run – und Sie erhalten alle Logs. Möchten Sie nur Warnungen? RUST_LOG=warn. Sehr praktisch für das Debugging von Rust-Anwendungen in Echtzeit.



3. Panik und Backtrace: Den Fehlerstapel lesen



Wenn ein Programm in Panik gerät, gibt Rust eine Meldung aus. Aber oft reicht das nicht. Aktivieren Sie den vollständigen Backtrace:



$ RUST_BACKTRACE=1 cargo run


Oder für maximale Detailtiefe:



$ RUST_BACKTRACE=full cargo run


Sie sehen den gesamten Aufrufstapel – vom Absturzpunkt bis zu main. Dies ist entscheidend beim Debugging von Rust-Code, wenn Sie nicht verstehen, woher der Fehler kommt.



Beispiel: Angenommen, Sie haben diesen Code:



fn main() {    let v = vec![1, 2, 3];    println!("{}", v[10]);  // Panik!}


Mit RUST_BACKTRACE=1 sehen Sie nicht nur "index out of bounds", sondern die genaue Zeile und den Aufruf.



4. Debug-Modus und Optimierungen: debug vs release



Ein wichtiger Punkt: Das Debugging von Rust-Code im debug-Modus (Standard) liefert vollständige Informationen. Aber im release-Modus optimiert der Compiler den Code, und einige Variablen können verschwinden oder ihre Reihenfolge ändern. Wenn Sie einen "Release"-Bug debuggen – verwenden Sie ein Profil mit Debug-Informationen:



[profile.release]debug = true


In Cargo.toml. Dies ermöglicht Ihnen, cargo run --release

Blogs

Buchempfehlungen