Handling Errors with Result and Option - Rust

 

Why Handle Errors? 

In Rust, handling errors is not just a good practice—it’s a survival skill!  Unlike some languages where errors pop up unexpectedly like a jump scare in a horror movie, Rust forces you to deal with them upfront.

Rust provides two powerful tools for error handling:

  1. Result<T, E> — For operations that can succeed or fail.
  2. Option<T> — For values that might exist or be absent.

Result<T, E>: Success or Failure?

A Result type represents an operation that could either be Ok(value) (success) or Err(error) (failure). Think of it as flipping a coin, but instead of heads or tails, you get success or an error message!

Example 1: Using Result for File Operations

use std::fs::File;
use std::io::Error;

fn open_file(filename: &str) -> Result<File, Error> {
    File::open(filename)
}

fn main() {
    match open_file("data.txt") {
        Ok(file) => println!("File opened successfully: {:?}", file),
        Err(error) => println!("Oops! Failed to open file: {}", error),
    }
}

Explanation:

  • File::open(filename) returns Result<File, Error>.
  • Ok(file) runs if opening succeeds.
  • Err(error) handles failures (e.g., file not found).

Option<T>: Is It There or Not?

The Option type is used when a value might be missing. It’s like checking if your fridge has cake. 

Example 2: Safe Division with Option

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

fn main() {
    match safe_divide(10.0, 2.0) {
        Some(result) => println!("Result: {}", result),
        None => println!("Division by zero? Nope, not today!"),
    }
}

Explanation:

  • If b == 0.0, return None (division by zero is bad).
  • Otherwise, return Some(result).
  • match handles both cases safely.

Error Handling Shortcuts

unwrap() — YOLO Mode 

If you're feeling brave (or reckless), you can use unwrap() to get the value inside Result or Option. But beware: if an error occurs, your program will panic and crash.

let file = File::open("data.txt").unwrap(); // Crashes if file doesn’t exist!

expect() — Unwrap with a Friendly Message

let file = File::open("data.txt").expect("Failed to open the file!");

This is like unwrap(), but it lets you add a custom error message before crashing! 

? Operator — The Chill Way

Instead of manually matching errors, the ? operator propagates them automatically.

fn read_file() -> Result<String, std::io::Error> {
    use std::fs;
    let content = fs::read_to_string("data.txt")?; // If error occurs, it gets returned immediately
    Ok(content)
}

Explanation:

  • If fs::read_to_string() succeeds, it continues.
  • If it fails, the error is returned immediately (no need for match).

Conclusion

  • Use Result<T, E> for operations that can succeed or fail.
  • Use Option<T> for values that might be missing.
  • Prefer ? operator for cleaner error handling.
  • Avoid unwrap() unless you love surprises (crashes).

Rust makes error handling less painful and more predictable.

Post a Comment

0 Comments