thiserror 和 anyhow

The thiserror and anyhow crates are widely used to simplify error handling.

  • thiserror is often used in libraries to create custom error types that implement From<T>.
  • anyhow is often used by applications to help with error handling in functions, including adding contextual information to your errors.
  1. use anyhow::{bail, Context, Result};
  2. use std::fs;
  3. use std::io::Read;
  4. use thiserror::Error;
  5. #[derive(Clone, Debug, Eq, Error, PartialEq)]
  6. #[error("Found no username in {0}")]
  7. struct EmptyUsernameError(String);
  8. fn read_username(path: &str) -> Result<String> {
  9. let mut username = String::with_capacity(100);
  10. fs::File::open(path)
  11. .with_context(|| format!("Failed to open {path}"))?
  12. .read_to_string(&mut username)
  13. .context("Failed to read")?;
  14. if username.is_empty() {
  15. bail!(EmptyUsernameError(path.to_string()));
  16. }
  17. Ok(username)
  18. }
  19. fn main() {
  20. //fs::write("config.dat", "").unwrap();
  21. match read_username("config.dat") {
  22. Ok(username) => println!("Username: {username}"),
  23. Err(err) => println!("Error: {err:?}"),
  24. }
  25. }

This slide should take about 5 minutes.

thiserror

  • The Error derive macro is provided by thiserror, and has lots of useful attributes to help define error types in a compact way.
  • The std::error::Error trait is derived automatically.
  • The message from #[error] is used to derive the Display trait.

anyhow

  • anyhow::Error is essentially a wrapper around Box<dyn Error>. As such it’s again generally not a good choice for the public API of a library, but is widely used in applications.
  • anyhow::Result<V> is a type alias for Result<V, anyhow::Error>.
  • Actual error type inside of it can be extracted for examination if necessary.
  • Functionality provided by anyhow::Result<T> may be familiar to Go developers, as it provides similar usage patterns and ergonomics to (T, error) from Go.
  • anyhow::Context is a trait implemented for the standard Result and Option types. use anyhow::Context is necessary to enable .context() and .with_context() on those types.