anyhow

The anyhow crate provides a rich error type with support for carrying additional contextual information, which can be used to provide a semantic trace of what the program was doing leading up to the error.

This can be combined with the convenience macros from thiserror to avoid writing out trait impls explicitly for custom error types.

use anyhow::{bail, Context, Result};
use std::fs;
use std::io::Read;
use thiserror::Error;

#[derive(Clone, Debug, Eq, Error, PartialEq)]
#[error("Found no username in {0}")]
struct EmptyUsernameError(String);

fn read_username(path: &str) -> Result<String> {
    let mut username = String::with_capacity(100);
    fs::File::open(path)
        .with_context(|| format!("Failed to open {path}"))?
        .read_to_string(&mut username)
        .context("Failed to read")?;
    if username.is_empty() {
        bail!(EmptyUsernameError(path.to_string()));
    }
    Ok(username)
}

fn main() {
    //fs::write("config.dat", "").unwrap();
    match read_username("config.dat") {
        Ok(username) => println!("Username: {username}"),
        Err(err) => println!("Error: {err:?}"),
    }
}
This slide should take about 5 minutes.
  • anyhow::Error は基本的に Box<dyn Error> のラッパーとなっています。そのため、ライブラリの公開 API としては一般的には適していませんが、アプリでは広く使用されています。
  • anyhow::Result<V>Result<V, anyhow::Error> の型エイリアスです。
  • Functionality provided by anyhow::Error may be familiar to Go developers, as it provides similar behavior to the Go error type and Result<T, anyhow::Error> is much like a Go (T, error) (with the convention that only one element of the pair is meaningful).
  • anyhow::Context は、標準の Result 型と Option 型に実装されたトレイトです。これらの型で .context().with_context() を有効にするには、use anyhow::Context が必要です。

その他

  • anyhow::Error has support for downcasting, much like std::any::Any; the specific error type stored inside can be extracted for examination if desired with Error::downcast.