anyhow

Крейт anyhow надає багатий тип помилок з підтримкою передачі додаткової контекстної інформації, яка може бути використана для семантичного відстеження дій програми, що призвели до виникнення помилки.

Це можна поєднати зі зручними макросами з thiserror, щоб уникнути написання реалізацій трейтів явно для користувацьких типів помилок.

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

#[derive(Clone, Debug, Eq, Error, PartialEq)]
#[error("Не знайдено імені користувача в {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!("Не вдалося відкрити {path}"))?
        .read_to_string(&mut username)
        .context("Не вдалося прочитати")?;
    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}"),
        Err(err) => println!("Помилка: {err:?}"),
    }
}
This slide should take about 5 minutes.
  • anyhow::Error по суті є обгорткою навколо Box<dyn Error>. Таким чином, це знову ж таки, як правило, не є хорошим вибором для загальнодоступного API бібліотеки, але широко використовується в програмах.
  • anyhow::Result<V> — це псевдонім типу для Result<V, anyhow::Error>.
  • Функціональність, яку надає anyhow::Error, може бути знайома розробникам Go, оскільки вона забезпечує поведінку, подібну до типу Go error, а Result<T, anyhow::Error> дуже схожа на Go (T, error) (з умовою, що тільки один елемент пари є значущим).
  • anyhow::Context - це трейт, реалізований для стандартних типів Result та Option. Використання anyhow::Context необхідне для того, щоб дозволити використання .context() та .with_context() для цих типів.

Більше інформації для вивчення

  • anyhow::Error має підтримку даункастингу, подібно до std::any::Any; конкретний тип помилки, що зберігається всередині, може бути витягнутий для вивчення за допомогою Error::downcast.