Things on this page are fragmentary and immature notes/thoughts of the author. Please read with your own judgement!
:timing
:sccache 1
Tips and Traps¶
The question mark
?is a sugar syntax ...eprintln!Result.expectis a more user friendly alternative toResult.unwrap.Result.expectallows you to define a customized error message. It is suggested that you useResult.expectinstead ofResult.unwrapwhere applicable. Of course, bothResult.expectandResult.unwrapare discouraged and it is suggested that you use pattern matching and handle errors explicitly.Result.okconverts aResultobject to anOptionobject. Symetrically,Option.ok_orconverts anOptionto aResultobject.The recommended way of error handling in Rust is to define an enum that covers meaningful error cases for your library, implement
Debug,Displayandstd::error::Errorfor that enum. This is fast/cheap (no heap allocation on error), and precise and easy to use.By default errors in Rust are checked (at compile time). However, you can get unchecked error using
Box<dyn std::error::Error + 'static>withSendandSync.The disscussion in The state of error handling in the 2018 edition suggests that thiserror (for libraries) + anyhow (for applications) is a good combination.
Rust Crates for Error Handling¶
thiserror¶
anyhow¶
miette¶
miette is a fancy diagnostic reporting library and protocol for us mere mortals who aren't compiler hackers.
:dep thiserror = "1.0.25"
:dep anyhow = "1.0.41"
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ParseRankError {
#[error("{0} is not a valid symbol for card rank!")]
InvalidSymbol(char),
#[error("{0} is not a valid integer for card rank!")]
InvalidInteger(u8),
}
let err = ParseRankError::InvalidSymbol('m');
err
err.to_string()
println!("{}", err);
println!("{:?}", err);
println!("{:?}: {}", err, err);
eprintln!("{:?}: {}", err, err);
use std::io;
let err = io::Error::new(io::ErrorKind::Other, "oh no!");
err
eprintln!("{:?}: {}", err, err);
println!("{:?}", io::Error::last_os_error());
use thiserror::Error;
/// WordCountError enumerates all possible errors returned by this library.
#[derive(Error, Debug)]
pub enum WordCountError {
/// Represents an empty source. For example, an empty text file being given
/// as input to `count_words()`.
#[error("Source contains no data")]
EmptySource,
/// Represents a failure to read from input.
#[error("Read error")]
ReadError { source: std::io::Error },
/// Represents all other cases of `std::io::Error`.
#[error(transparent)]
IOError(#[from] std::io::Error),
}
/// WordCountError enumerates all possible errors returned by this library.
#[derive(Debug)]
enum WordCountError {
/// Represents an empty source. For example, an empty text file being given
/// as input to `count_words()`.
EmptySource,
/// Represents a failure to read from input.
ReadError { source: std::io::Error },
/// Represents all other cases of `std::io::Error`.
IOError(std::io::Error),
}
impl std::error::Error for WordCountError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self {
WordCountError::EmptySource => None,
WordCountError::ReadError { ref source } => Some(source),
WordCountError::IOError(_) => None,
}
}
}
impl std::fmt::Display for WordCountError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match *self {
WordCountError::EmptySource => {
write!(f, "Source contains no data")
}
WordCountError::ReadError { .. } => {
write!(f, "Read error")
}
WordCountError::IOError(ref err) => {
err.fmt(f)
}
}
}
}
impl From<std::io::Error> for WordCountError {
fn from(err: std::io::Error) -> WordCountError {
WordCountError::IOError(err)
}
}