Rust Interview Questions

35 Questions
Rust

Rust

Web DevelopmentIoT

Question 13

What is the Result type in Rust?

Answer:

The Result type in Rust is an enum used for error handling. It represents either a success or a failure, providing a type-safe way to handle operations that can fail. The Result type is defined in the standard library and is commonly used for functions that can produce errors.

Definition

The Result enum is defined as follows:

enum Result<T, E> {
    Ok(T),
    Err(E),
}
  • Ok(T): Indicates that the operation was successful and contains a value of type T.
  • Err(E): Indicates that the operation failed and contains an error of type E.

Usage

Creating and Returning Result

You can create and return a Result from a function to indicate success or failure:

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),
    }

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

Unwrapping Result

If you are sure that a Result is Ok, you can use the unwrap method. However, this will panic if the Result is Err.

fn main() {
    let result = divide(10.0, 2.0);
    println!("Unwrapped result: {}", result.unwrap());

    // This will panic
    // let error_result = divide(10.0, 0.0);
    // println!("Unwrapped error: {}", error_result.unwrap());
}

Handling Errors Gracefully

You can use methods like unwrap_or, unwrap_or_else, and unwrap_or_default to provide default values or handle errors more gracefully.

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);
}

Chaining Operations with and_then

You can chain operations that return Result using the and_then method.

fn square_root(number: f64) -> Result<f64, String> {
    if number < 0.0 {
        Err(String::from("Cannot take the square root of a negative number"))
    } else {
        Ok(number.sqrt())
    }
}

fn main() {
    let result = divide(9.0, 3.0).and_then(square_root);
    match result {
        Ok(value) => println!("Square root of division result: {}", value),
        Err(e) => println!("Error: {}", e),
    }
}

Using ? Operator for Propagation

The ? operator can be used to propagate errors. If a function call returns Err, the ? operator will return the error from the calling function. If it returns Ok, the value is unwrapped and returned.

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),
    }
}

Summary

  • Definition: Result is an enum that can be Ok(T) for a success or Err(E) for a failure.
  • Creating: Functions can return Result to indicate success (Ok) or failure (Err).
  • Unwrapping: Use unwrap, unwrap_or, unwrap_or_else, or unwrap_or_default to handle Result.
  • Chaining: Use and_then for chaining operations that return Result.
  • Error Propagation: Use the ? operator to propagate errors easily.

The Result type provides a robust and flexible way to handle errors in Rust, making error handling explicit and type-safe.

Recent job openings