anyhow
anyhow クレートは、追加のコンテキスト情報を保持できるリッチなエラー型を提供します。これは、エラーに至るまでプログラムが何をしていたかの意味的なトレースを提供するために使用できます。
これを thiserror の便利なマクロと組み合わせることで、カスタムエラー型に対するトレイト実装を明示的に書く必要を避けられます。
// Copyright 2024 Google LLC // SPDX-License-Identifier: Apache-2.0 use anyhow::{Context, Result, bail}; 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:?}"), } }
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型に対して実装されているトレイトです。これらの型で.context()と.with_context()を有効にするにはuse anyhow::Contextが必要です。
さらに調べるには
anyhow::Errorはstd::any::Anyと同様にダウンキャストをサポートしています。必要であれば、内部に格納されている具体的なエラー型を取り出して調べることができます。これにはError::downcastを使用します。