Defining custom error types in Rust typically involves several steps and leverages specific Rust features. Here is a step-by-step approach to defining a custom error type:
-
Using
enumorstruct: Custom errors are typically defined usingenumorstruct.enumis better suited for representing multiple distinct error types, whilestructis appropriate for simpler or single-type errors. -
Implementing the
std::fmt::Debugandstd::fmt::Displaytraits: This allows errors to be displayed in a developer-friendly manner.Debugis automatically derived, whereasDisplaytypically requires manual implementation. -
Implementing the
std::error::Errortrait: This is essential for making the type an error type. Although not strictly required, doing so ensures compatibility with Rust's error handling ecosystem.
Below is a simple example demonstrating how to define a custom error type:
rustuse std::fmt; // Define an `enum` to represent different error cases #[derive(Debug)] enum MyError { Io(std::io::Error), Parse(std::num::ParseIntError), Other(String), } // Implement `Display` for `MyError`. This is typically used to display error information to users. impl fmt::Display for MyError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { MyError::Io(err) => write!(f, "IO error: {}", err), MyError::Parse(err) => write!(f, "Parse error: {}", err), MyError::Other(msg) => write!(f, "An error occurred: {}", msg), } } } // Implement `std::error::Error`. // For this simple example, we can directly use the default implementation of `std::error::Error`. impl std::error::Error for MyError {} // Usage example fn main() -> Result<(), MyError> { let result = do_something_that_might_fail()?; println!("Success: {}", result); Ok(()) } fn do_something_that_might_fail() -> Result<i32, MyError> { let input = "not a number"; let num: i32 = input.parse().map_err(MyError::Parse)?; Ok(num) }
In this example, the MyError type defines three possible error cases: an I/O error, a parsing error when converting a string to an integer, and a generic string error message. The implementation of the Display and Error traits ensures this type functions properly within Rust's error handling ecosystem.
When using the ? operator in the do_something_that_might_fail function and encountering an error, it automatically converts std::num::ParseIntError to MyError because we provide a conversion method from ParseIntError to MyError (via map_err).
This approach enables you to handle various error types by using this custom error type to pass error information between your code segments.