Rust Error Handling
Error Handling in Rust:
Rust provides robust error handling mechanisms through its Result and Option types.
The following types of check techniques help the personnel mitigate loss as a result of recoverable and unrecoverable errors.
Handling Errors Using Result and Option Types
Result Type:
The Result type is used by functions that can have an error returning it. It is an enum with two variants:It is an enum with two variants:
- Ok(T): Indicates that the operation was successful, containing the result.
- Err(E): Indicates that an error occurred, containing the error.
Example:
fn divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
Err(String::from("Division by zero"))
} else {
Ok(a / b)
}
}
fn main() {
match divide(10.0, 2.0) {
Ok(result) => println!("Result: {}", result),
Err(e) => println!("Error: {}", e),
}
}
Option Type:
The Option type is used for values that may or may not be present. It is an enum with two variants:
- Some(T): Indicates that a value is present.
- None: Indicates that no value is present.
Example:
fn find_value(vec: Vec<i32>, target: i32) -> Option<usize> {
for (index, &value) in vec.iter().enumerate() {
if value == target {
return Some(index);
}
}
None
}
fn main() {
let numbers = vec![1, 2, 3, 4, 5];
match find_value(numbers, 3) {
Some(index) => println!("Found at index: {}", index),
None => println!("Not found"),
}
}
Propagating Errors with the ? Operator
The ? operator is a shorthand for propagating errors.
If the result equals Ok, we use the value; if the result does not equalOk, we return the error from the current funciton.
Example:
use std::fs::File;
use std::io::{self, Read};
fn read_file(path: &str) -> Result<String, io::Error> {
let mut file = File::open(path)?; // Propagates error if File::open fails
let mut contents = String::new();
file.read_to_string(&mut contents)?; // Propagates error if read_to_string fails
Ok(contents)
}
fn main() {
match read_file("hello.txt") {
Ok(contents) => println!("File contents: {}", contents),
Err(e) => println!("Error reading file: {}", e),
}
}
Custom Error Types
Creating custom error types can help in handling domain-specific errors more effectively.
You can define your own error types and implement the std::fmt::Debug, std::fmt::Display, and std::error::Error traits.
Example:
use std::fmt;
#[derive(Debug)]
enum MyError {
NotFound,
InvalidInput,
}
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
MyError::NotFound => write!(f, "Item not found"),
MyError::InvalidInput => write!(f, "Invalid input provided"),
}
}
}
impl std::error::Error for MyError {}
fn find_item(vec: Vec<i32>, target: i32) -> Result<i32, MyError> {
for &item in vec.iter() {
if item == target {
return Ok(item);
}
}
Err(MyError::NotFound)
}
fn main() {
match find_item(vec![1, 2, 3, 4, 5], 6) {
Ok(item) => println!("Found item: {}", item),
Err(e) => println!("Error: {}", e),
}
}
Rust error handling is done very effectively with powerful and flexible facilities to aid safety purpose for the programming code.