Exerpad
🔥1
10 XP
Lv.1 Beginner
Log In

Handling Errors

In Rust, there are no exceptions like in Python or JavaScript. Instead, Rust uses two special types to handle situations where something might go wrong: Result and Option.

Option — Maybe There's a Value

Option represents a value that might or might not exist:

rust
fn main() {
let numbers = vec![10, 20, 30];
let first = numbers.get(0); // Some(&10)
let tenth = numbers.get(9); // None
println!("First: {:?}", first);
println!("Tenth: {:?}", tenth);
}

An Option is either Some(value) or None. The .get() method on vectors returns an Option because the index might be out of bounds.

Matching on Option

You can use match to handle both cases:

rust
fn main() {
let fruits = vec!["apple", "banana", "cherry"];
match fruits.get(1) {
Some(fruit) => println!("Found: {}", fruit),
None => println!("Nothing there!"),
}
}

unwrap and expect

If you're sure a value exists, you can use .unwrap() to get it directly. But if it's None, your program will crash!

rust
fn main() {
let numbers = vec![42];
let value = numbers.get(0).unwrap();
println!("Got: {}", value);
}

.expect("message") does the same but shows your custom message if it crashes:

rust
fn main() {
let numbers = vec![42];
let value = numbers.get(0).expect("List should not be empty");
println!("Got: {}", value);
}

unwrap_or — Safe Default

Instead of crashing, you can provide a default value:

rust
fn main() {
let numbers: Vec<i32> = vec![];
let value = numbers.get(0).unwrap_or(&0);
println!("Got: {}", value);
}

Result — Success or Error

Result is for operations that might fail. It's either Ok(value) or Err(error):

rust
fn main() {
let good: Result<i32, String> = Ok(42);
let bad: Result<i32, String> = Err(String::from("something went wrong"));
println!("Good: {:?}", good);
println!("Bad: {:?}", bad);
}

A common example is parsing strings to numbers:

rust
fn main() {
let num: Result<i32, _> = "42".parse();
let oops: Result<i32, _> = "hello".parse();
println!("Parsed: {:?}", num);
println!("Failed: {:?}", oops);
}

Matching on Result

rust
fn main() {
let input = "256";
match input.parse::<i32>() {
Ok(n) => println!("Number is: {}", n),
Err(e) => println!("Error: {}", e),
}
}

The ? Operator

In functions that return Result, you can use ? to pass errors up automatically:

rust
fn double_parse(text: &str) -> Result<i32, std::num::ParseIntError> {
let n = text.parse::<i32>()?;
Ok(n * 2)
}

fn main() {
match double_parse("21") {
Ok(n) => println!("Result: {}", n),
Err(e) => println!("Error: {}", e),
}
}

The ? means: "If this is Ok, unwrap it. If it's Err, return the error immediately."

Summary

ConceptWhat it does
Option<T>A value that might be Some(T) or None
Result<T, E>A result that's Ok(T) or Err(E)
.unwrap()Gets the value or crashes
.expect("msg")Gets the value or crashes with a message
.unwrap_or(&default)Gets the value or uses a default
match on Option/ResultHandle each case explicitly
? operatorPass errors up to the caller

Now let's practice handling errors!