rust error handling

In Rust, error handling is an important aspect of writing robust and reliable code. Rust provides several mechanisms for handling errors, including the Result and Option types, as well as the panic! macro for handling unrecoverable errors.

The Result type is used to represent the possibility of an error occurring. It has two variants: Ok, which holds a value when the operation is successful, and Err, which holds an error value when the operation fails. You can use pattern matching or the unwrap() method to extract the value from a Result or handle the error case, respectively.

Here's an example that demonstrates the usage of Result:

use std::fs::File;
use std::io::Read;

fn read_file_contents(path: &str) -> Result<String, std::io::Error> {
    let mut file = File::open(path)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;

    Ok(contents)
}

fn main() {
    match read_file_contents("example.txt") {
        Ok(contents) => println!("File contents: {}", contents),
        Err(error) => eprintln!("Error reading file: {}", error),
    }
}

In this example, the read_file_contents function attempts to open a file and read its contents. It returns a Result indicating success or failure. Inside the main function, we use pattern matching to handle the Result. If the Result is Ok, we print the file contents. Otherwise, we print an error message.

The Option type is similar to Result, but it is used when a value may or may not be present. It has two variants: Some, which holds a value, and None, which represents the absence of a value. You can use pattern matching or the unwrap() method to extract the value from an Option or handle the absence case, respectively.

Here's an example that demonstrates the usage of Option:

fn divide(a: f64, b: f64) -> Option<f64> {
    if b == 0.0 {
        None
    } else {
        Some(a / b)
    }
}

fn main() {
    let result = divide(10.0, 2.0);

    match result {
        Some(value) => println!("Result: {}", value),
        None => println!("Error: Division by zero"),
    }
}

In this example, the divide function attempts to divide two numbers. It returns an Option indicating success or failure. Inside the main function, we use pattern matching to handle the Option. If the Option is Some, we print the result. Otherwise, we print an error message.

Finally, the panic! macro can be used to cause the program to abort with an error message. This is typically used for unrecoverable errors, such as when a precondition is violated or when an unexpected condition occurs.

fn sqrt(x: f64) -> f64 {
    if x >= 0.0 {
        x.sqrt()
    } else {
        panic!("Square root of a negative number is undefined")
    }
}

fn main() {
    sqrt(-1.0);
}

In this example, the sqrt function calculates the square root of a number. If the number is negative, the panic! macro is used to abort the program with an error message.