Rust-Fehlerbehandlungsbibliotheken

  • thiserror bietet praktische Ableitungsmakros für benutzerdefinierte Fehlertypen.

  • snafu ist ein Fehlerbehandlungs- und Berichtsframework mit Kontextunterstützung.

  • anyhow ist eine flexible Fehlerbehandlungs- und Berichtsbibliothek.

thiserror vs snafu

thiserror

thiserror ist eine leichtgewichtige Bibliothek, die Ableitungsmakros zur Vereinfachung von Fehlerdefinitionen bereitstellt.

Merkmale:

  • Prägnante Syntax mit geringem Aufwand
  • Geeignet für die Erstellung von Fehlertyp-Bibliotheken und APIs
  • Typischerweise für Bibliotheken verwendet, die für andere bestimmt sind
use thiserror::Error;

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

snafu

snafu bietet ein umfassenderes Fehlerbehandlungsframework mit Fokus auf Fehlerkontext und Fehlerverkettung.

Merkmale:

  • Ermutigt präzisere Fehlerkontext-Ergänzung durch das "Kontext-Selektor"-Muster
  • Fördert das "Ein-Fehler-Enum-pro-Modul"-Muster
  • Unterstützt sowohl Struct- als auch Tupel-Stil-Fehlervarianten
  • Eingebaute Backtrace-Unterstützung
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-Stil wird ebenfalls unterstützt
    #[snafu(display("E/A-Fehler"))]
    Io(#[snafu(source)] std::io::Error, #[snafu(backtrace)] Backtrace),
}

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

Vergleich

Merkmalthiserrorsnafu
Syntax-PrägnanzPrägnanterAusführlicher
FehlerkontextGrundlegende UnterstützungUmfangreiche Kontextmechanismen
Geeigneter UmfangKleine bis mittlere ProjekteMittlere bis große Projekte
Zeilen pro Fehler~2 Zeilen pro Fehler~5 Zeilen pro Fehler
FehlerorganisationNormalerweise ein Fehler-EnumFördert modulbezogene Fehler-Enums
Backtrace-UnterstützungKeine eingebaute UnterstützungEingebaute Unterstützung

Auswahlberatung:

  • Wählen Sie thiserror, wenn Sie einfache und klare Fehlertypen benötigen, insbesondere in Bibliotheken
  • Wählen Sie snafu, wenn Sie strukturiertere Fehlerbehandlung benötigen, besonders in großen Anwendungen

anyhow

anyhow ist eine andere Fehlerbehandlungsbibliothek als die beiden oben genannten, mit Fokus auf Anwendungen statt Bibliotheken.

Merkmale:

  • Entwickelt für Fehlerbehandlung in Anwendungen, nicht in Bibliotheken
  • Bietet einen dynamischen anyhow::Error-Typ, der jeden Fehler enthalten kann, der das Error-Trait implementiert
  • Vereinfacht die Handhabung über mehrere Fehlertypen hinweg
  • Keine Notwendigkeit, benutzerdefinierte Fehlertypen zu definieren
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")?;
        
    // Verwendung von Result<T> als Typalias für Result<T, anyhow::Error>
    Ok(())
}

anyhow vs thiserror/snafu:

  • anyhow konzentriert sich auf Fehlerbehandlung während der schnellen Anwendungsentwicklung
  • thiserror/snafu konzentrieren sich auf die Erstellung präziser Fehlertyp-Hierarchien
  • anyhow wird typischerweise im Anwendungscode verwendet
  • thiserror/snafu werden typischerweise im Bibliothekscode verwendet

In der Praxis werden anyhow und thiserror oft zusammen verwendet: Bibliotheken nutzen thiserror zur Definition präziser Fehlertypen, während Anwendungen anyhow zur Behandlung von Fehlern aus verschiedenen Quellen verwenden.