Rust Interview Questions

35 Questions
Rust

Rust

Web DevelopmentIoT

Question 14

How do you handle errors in Rust?

Answer:

Handling errors in Rust involves using the Result and Option types, along with various methods and the ? operator to manage and propagate errors effectively. Here's a comprehensive guide on how to handle errors in Rust:

Using Result and Option

1. Result Type

The Result type is used for functions that can return an error. It is defined as:

enum Result<T, E> {
    Ok(T),
    Err(E),
}
  • Ok(T): Indicates a successful result containing a value of type T.
  • Err(E): Indicates an error containing a value of type E.

2. Option Type

The Option type is used for values that may or may not be present. It is defined as:

enum Option<T> {
    Some(T),
    None,
}
  • Some(T): Contains a value of type T.
  • None: Represents the absence of a value.

Handling Result and Option

1. Using match Statements

You can handle Result and Option values using match statements to explicitly handle success and failure cases.

fn divide(numerator: f64, denominator: f64) -> Result<f64, String> {
    if denominator == 0.0 {
        Err(String::from("Cannot divide by zero"))
    } else {
        Ok(numerator / denominator)
    }
}

fn main() {
    match divide(4.0, 2.0) {
        Ok(result) => println!("Result: {}", result),
        Err(e) => println!("Error: {}", e),
    }
}

2. Using Methods like unwrap, unwrap_or, and unwrap_or_else

You can use these methods to handle Result and Option values more concisely.

fn main() {
    let result = divide(10.0, 2.0).unwrap_or(0.0);
    println!("Result or default: {}", result);

    let result = divide(10.0, 0.0).unwrap_or_else(|err| {
        println!("Handling error: {}", err);
        0.0
    });
    println!("Result or handled error: {}", result);
}

3. Using the ? Operator

The ? operator can be used to propagate errors. It can only be used in functions that return Result or Option.

fn read_number_from_file(file_path: &str) -> Result<f64, Box<dyn std::error::Error>> {
    let content = std::fs::read_to_string(file_path)?;
    let number: f64 = content.trim().parse()?;
    Ok(number)
}

fn main() {
    match read_number_from_file("number.txt") {
        Ok(number) => println!("Number from file: {}", number),
        Err(e) => println!("Error: {}", e),
    }
}

Custom Error Types

1. Defining Custom Error Types

You can define your own error types to provide more specific error handling.

#[derive(Debug)]
enum CustomError {
    IoError(std::io::Error),
    ParseError(std::num::ParseFloatError),
}

impl From<std::io::Error> for CustomError {
    fn from(error: std::io::Error) -> Self {
        CustomError::IoError(error)
    }
}

impl From<std::num::ParseFloatError> for CustomError {
    fn from(error: std::num::ParseFloatError) -> Self {
        CustomError::ParseError(error)
    }
}

fn read_number_from_file(file_path: &str) -> Result<f64, CustomError> {
    let content = std::fs::read_to_string(file_path)?;
    let number: f64 = content.trim().parse()?;
    Ok(number)
}

fn main() {
    match read_number_from_file("number.txt") {
        Ok(number) => println!("Number from file: {}", number),
        Err(e) => println!("Error: {:?}", e),
    }
}

Using Result with Multiple Error Types

Rust's Result type can handle multiple error types using the From trait to convert errors into a common error type.

fn read_file(file_path: &str) -> Result<String, Box<dyn std::error::Error>> {
    let content = std::fs::read_to_string(file_path)?;
    Ok(content)
}

fn parse_number(content: &str) -> Result<f64, Box<dyn std::error::Error>> {
    let number: f64 = content.trim().parse()?;
    Ok(number)
}

fn main() {
    let result = read_file("number.txt").and_then(|content| parse_number(&content));
    match result {
        Ok(number) => println!("Parsed number: {}", number),
        Err(e) => println!("Error: {}", e),
    }
}

Summary

Rust provides robust tools for error handling with the Result and Option types. Using these types, along with methods like unwrap, unwrap_or, and unwrap_or_else, and the ? operator, you can handle errors effectively and write safer, more reliable code. Custom error types and the ability to convert between error types using the From trait provide further flexibility in managing errors in complex applications.

Recent job openings