Gestiunea Idiomatică a Erorilor în Rust: thiserror pentru Biblioteci și anyhow pentru Aplicații în Rust

Ghid complet pentru tratarea erorilor în Rust: dihotomia enterprise dintre erori puternic tipizate cu thiserror (pentru biblioteci) și raportare bogată în context cu anyhow (pentru aplicații și microservicii).

Sintaxă
#[derive(thiserror::Error, Debug)] | anyhow::Context | anyhow::Result<T>

Rust nu posedă un mecanism de excepții tradiționale (precum try/catch/throw din Java sau C++), considerând că excepțiile ascunse introduc fluxuri invizibile de control ce fac codul greu de auditat și de depanat. În schimb, erorile recuperabile sunt valori de prim rang reprezentate prin tipul enumerare Result.

În industria software profesională, tratarea erorilor în Rust urmează o distincție clară între Biblioteci și Aplicații:

1. În Biblioteci: Erori Structurate și Exhaustive cu thiserror
use thiserror::Error;

// Crate-ul 'thiserror' sintetizează automat implementările trait-urilor 
// std::error::Error și std::fmt::Display pe baza atributelor declarative:
#[derive(Error, Debug)]
pub enum EroareClientHttp {
    #[error("Eroare I/O de rețea la conectarea cu {host}:{port}")]
    EroareRetea {
        host: String,
        port: u16,
        #[source] // Indică eroarea cauzală originală
        sursa: std::io::Error,
    },

    #[error("Răspuns invalid primit de la server (cod HTTP {0})")]
    StatusInvalid(u16),

    #[error("Deserializarea JSON a eșuat")]
    FormatJsonIncompatibil(#[from] serde_json::Error),
}
2. În Aplicații și Microservicii: Context Dinamic cu anyhow
use anyhow::{Context, Result};

// În fișierele binare (main.rs), folosim anyhow::Result pentru a acumula 
// mesaje clare de context pe măsură ce eroarea urcă prin stivă:
fn citeste_configuratie() -> Result {
    let cale = "/etc/app/config.json";
    
    // Metoda .with_context() adaugă informații valoroase pentru inginerul de on-call:
    let continut = std::fs::read_to_string(cale)
        .with_context(|| format!("Nu s-a putut deschide fișierul de configurare: {}", cale))?;

    Ok(continut)
}

fn main() -> Result<()> {
    let cfg = citeste_configuratie()?;
    println!("Configuratie incarcata: {}", cfg);
    Ok(())
}

Comparație: thiserror vs. anyhow

Caracteristică thiserror anyhow
Scenariu Țintă Biblioteci (Crates / SDK-uri) Aplicații (Binaries, CLI, Web APIs)
Tip Returnat Enumerare proprie tipizată static (MyLibError) Wrapper dinamic tip anyhow::Error (pe heap)
Matching pe Erori Permite utilizatorului să facă match pe cazuri specifice Focalizat pe afișarea lanțului de erori (Backtrace / Cause)