Rust Fehlerbehandlungsbibliotheken

thiserrorBietet bequeme Ableitungsmakros für benutzerdefinierte Fehlertypen
snafuEin Framework für Fehlerbehandlung und -berichterstattung mit Kontext
anyhowFlexible Bibliothek für Fehlerbehandlung und -berichterstattung

thiserror vs snafu

thiserror

thiserror ist eine leichtgewichtige Bibliothek, die Ableitungsmakros für einfache Fehlerdefinitionen bereitstellt.

Merkmale:

  • Prägnante Syntax mit geringem Boilerplate
  • Ideal für die Erstellung von Fehlertyp-Bibliotheken und APIs
  • Wird typischerweise für Bibliotheken verwendet, die von anderen genutzt werden
use thiserror::Error;

#[derive(Error, Debug)]
pub enum DataError {
    #[error("Datenbankfehler: {0}")]
    DatabaseError(#[from] sqlx::Error),
    
    #[error("Validierungsfehler: {0}")]
    ValidationError(String),
    
    #[error("Eintrag nicht gefunden")]
    NotFound,
}

snafu

snafu bietet ein umfassenderes Framework für Fehlerbehandlung mit Fokus auf Fehlerkontext und -verketung.

Merkmale:

  • Fördert präzise Hinzufügung von Fehlerkontext durch "Context Selector"-Muster
  • Empfiehlt "Ein Fehlertyp pro Modul"-Ansatz
  • Unterstützt strukturierte und Tupel-Varianten für Fehler
  • Eingebaute Unterstützung für Backtraces
use snafu::{Snafu, ResultExt, Backtrace};

#[derive(Debug, Snafu)]
pub enum Error {
    #[snafu(display("Konfigurationsdatei {filename:?} konnte nicht gelesen werden"))]
    ReadConfig {
        filename: String,
        source: std::io::Error,
        backtrace: Backtrace,
    },
    
    // Tupel-Variante
    #[snafu(display("IO-Fehler aufgetreten"))]
    Io(#[snafu(source)] std::io::Error, #[snafu(backtrace)] Backtrace),
}

// Beispiel für Context Selector
fn read_config(path: &str) -> Result<Config, Error> {
    std::fs::read_to_string(path).context(ReadConfigSnafu { filename: path })?;
    // ...
}

Vergleich

Merkmalthiserrorsnafu
Syntax-EinfachheitPrägnanterAusführlicher
FehlerkontextGrundlegende UnterstützungUmfangreiche Kontextmechanismen
ProjektskalaKleine bis mittlere ProjekteMittlere bis große Projekte
CodezeilenCa. 2 Zeilen pro FehlerCa. 5 Zeilen pro Fehler
FehlerorganisationTypisch ein zentraler FehlertypFördert modulspezifische Fehlertypen
Backtrace-UnterstützungKeine eingebaute UnterstützungEingebaute Unterstützung

Empfehlungen:

  • thiserror wählen für einfache Fehlertypen, besonders in Bibliotheken
  • snafu wählen für strukturierte Fehlerbehandlung in größeren Anwendungen

anyhow

anyhow ist ein anderer Ansatz zur Fehlerbehandlung, der sich auf Anwendungen statt Bibliotheken konzentriert.

Merkmale:

  • Entwickelt für Fehlerbehandlung in Anwendungen, nicht Bibliotheken
  • Bietet dynamischen anyhow::Error-Typ für beliebige Fehler
  • Vereinfacht den Umgang mit verschiedenen Fehlertypen
  • Keine Definition benutzerdefinierter Fehlertypen nötig
use anyhow::{Context, Result};

fn main() -> Result<()> {
    let config = std::fs::read_to_string("config.json")
        .context("Konfigurationsdatei konnte nicht gelesen werden")?;
        
    let app_config: AppConfig = serde_json::from_str(&config)
        .context("Ungültiges Konfigurationsformat")?;
        
    // Result<T> als Alias für Result<T, anyhow::Error>
    Ok(())
}

anyhow vs thiserror/snafu:

  • anyhow fokussiert auf schnelle Fehlerbehandlung in Anwendungen
  • thiserror/snafu fokussieren auf präzise Fehlertyp-Hierarchien
  • anyhow typisch für Anwendungscode
  • thiserror/snafu typisch für Bibliothekscode

In der Praxis werden anyhow und thiserror oft kombiniert: Bibliotheken definieren präzise Fehlertypen mit thiserror, während Anwendungen anyhow für die Fehlerbehandlung nutzen.