Rust thiserror
This article delves into a Rust program that showcases custom error handling, parsing, and validation.
By leveraging the thiserror crate, we create descriptive error types to manage various parsing scenarios robustly.
We’ll explore how the program defines an Animal struct, parses and validates integer strings, and utilizes generics and traits for flexible error reporting.
Whether you’re new to Rust or looking to deepen your understanding of error handling and type safety, this step-by-step guide will help you grasp these essential concepts and apply them effectively in your Rust projects.
Webdock โ Fast Cloud VPS Linux Hosting

Importing Dependencies
use std::fmt;
use std::num::{ParseIntError, IntErrorKind};
use thiserror::Error;
std::fmt: Used for formatting and printing.std::num::{ParseIntError, IntErrorKind}: These are error types related to parsing integers.thiserror::Error: A crate used for deriving error types in a more convenient way.
Defining Custom Errors
#[derive(Debug, Error)]
pub enum MyError {
#[error("Failed to parse integer: {0}")]
ParseError(#[from] ParseIntError),
#[error("Value cannot be negative")]
NegativeValue,
#[error("Value exceeds maximum allowed for u8")]
Overflow,
}
#[derive(Debug, Error)]: This macro derives theDebugandErrortraits for theMyErrorenum.pub enum MyError: Defines a public enumMyErrorwhich represents different kinds of errors.ParseError(#[from] ParseIntError): Wraps aParseIntErrorwith a custom error message.NegativeValue: Represents an error when a value is negative.Overflow: Represents an error when a value exceeds the maximum allowed foru8.
Defining a Struct
#[derive(Debug)]
struct Animal {
name: String,
age: u8,
}
#[derive(Debug)]: Derives theDebugtrait for theAnimalstruct, allowing it to be formatted using{:?}.struct Animal: Defines a structAnimalwith two fields:name: AStringrepresenting the animal’s name.age: Au8representing the animal’s age.
Display Function
fn display<T: fmt::Debug>(value: Result<T, MyError>) {
match value {
Ok(val) => println!("Here's your value: {:?}", val),
Err(e) => println!("An error occurred: {:?}", e),
}
}
fn display<T: fmt::Debug>: A generic function that takes aResult<T, MyError>.match value: Matches on the result:Ok(val): If the result isOk, prints the value.Err(e): If the result isErr, prints the error.
Parsing and Validating Function
fn parse_and_validate(value_str: &str) -> Result<u8, MyError> {
let parsed: i64 = value_str.parse().map_err(MyError::from)?;
if parsed < 0 {
Err(MyError::NegativeValue)
} else if parsed > u8::MAX as i64 {
Err(MyError::Overflow)
} else {
Ok(parsed as u8)
}
}
fn parse_and_validate(value_str: &str) -> Result<u8, MyError>: Takes a string slice and returns aResult<u8, MyError>.let parsed: i64 = value_str.parse().map_err(MyError::from)?: Tries to parse the string toi64and maps anyParseIntErrortoMyError::ParseError.if parsed < 0: Checks if the parsed value is negative.Err(MyError::NegativeValue): Returns aNegativeValueerror.
else if parsed > u8::MAX as i64: Checks if the parsed value exceeds the maximum value foru8.Err(MyError::Overflow): Returns anOverflowerror.
else: If the value is valid, converts it tou8and returnsOk(parsed as u8).
Main Function
fn main() {
let cat = Animal {
name: "Whiskers".to_string(),
age: 3,
};
let number_str = "-30";
let number = parse_and_validate(number_str);
display(Ok(cat));
display(number);
}
fn main(): The main entry point of the program.let cat = Animal { ... }: Creates an instance ofAnimal.let number_str = "-30";: A string representing a number.let number = parse_and_validate(number_str);: Tries to parse and validate the string.display(Ok(cat));: Displays theAnimalinstance.display(number);: Displays the result ofparse_and_validate.
Conclusion
This code demonstrates:
- Custom error handling using the
thiserrorcrate. - Parsing and validating user input.
- Using generics and traits to handle different types and errors gracefully.
- Struct creation and usage in Rust.
By breaking down each part, we’ve shown how Rust’s powerful type system and error handling mechanisms can be used to write robust and readable code.

