Rust Result Type
Many actions can fail: opening a file, reading a number, or contacting a server. Rust represents the outcome with the Result type. Think of a parcel delivery: the package arrives intact, or the courier hands you a note explaining the problem. Result carries one of those two outcomes, and the compiler requires you to handle both.
The Shape of Result
Result is an enum with two variants.
enum Result<T, E> {
Ok(T),
Err(E),
}
Result<T, E>
/ \
Ok(T) Err(E)
success value error value
The letter T stands for the success type, and E stands for the error type. A function that parses a number returns Result<i32, ParseIntError>.
Returning a Result
The function below divides two numbers and refuses to divide by zero.
fn divide(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 {
Err(String::from("Cannot divide by zero"))
} else {
Ok(a / b)
}
}Handling a Result with match
A match expression opens the parcel and reacts to each outcome.
fn main() {
match divide(10.0, 4.0) {
Ok(answer) => println!("Answer: {answer}"),
Err(message) => println!("Problem: {message}"),
}
match divide(5.0, 0.0) {
Ok(answer) => println!("Answer: {answer}"),
Err(message) => println!("Problem: {message}"),
}
}
Answer: 2.5 Problem: Cannot divide by zero
Results in the Standard Library
Many standard functions return Result. Parsing text is a common case.
let good = "125".parse::<i32>();
let bad = "12x".parse::<i32>();
println!("{:?}", good);
println!("{:?}", bad);
Ok(125)
Err(ParseIntError { kind: InvalidDigit })
Opening a File
File operations return io::Result, a shortcut for a Result with an input-output error.
use std::fs::File;
fn main() {
match File::open("notes.txt") {
Ok(_) => println!("File opened"),
Err(e) => println!("Could not open file: {e}"),
}
}Useful Helper Methods
Helper methods shorten common patterns.
| Method | Purpose |
|---|---|
| is_ok() / is_err() | Tests the variant without extracting |
| unwrap_or(value) | Gives a fallback on Err |
| map(function) | Transforms the Ok value |
| map_err(function) | Transforms the Err value |
| and_then(function) | Chains another step that may fail |
| ok() | Converts Result into Option |
Transforming Success Values
let doubled = "21".parse::<i32>().map(|n| n * 2);
println!("{:?}", doubled); // Ok(42)Chaining Steps
The and_then method runs a second fallible step only when the first one succeeded.
fn check_age(age: i32) -> Result<i32, String> {
if age >= 18 { Ok(age) } else { Err(String::from("Too young")) }
}
let result = "20".parse::<i32>()
.map_err(|e| e.to_string())
.and_then(check_age);
println!("{:?}", result);
Ok(20)
parse --Ok--> check_age --Ok--> final Ok | | Err Err | | +-----> final Err
Ignoring a Result Is a Warning
Rust marks Result as must_use. Dropping one without looking at it triggers a compiler warning, because a hidden failure often turns into a hard-to-find bug.
Choosing Error Types
Small programs use String or a library error directly. Larger programs define custom error types that describe each failure precisely. Choose the simplest option that gives callers enough detail.
Result Compared with Option
| Type | Variants | Use When |
|---|---|---|
| Option | Some, None | A value may be absent, and absence is normal |
| Result | Ok, Err | An action may fail, and the reason matters |
Common Mistakes
Calling unwrap on every Result removes the safety the type provides. Match on the value or use helper methods so failures produce friendly messages.
Returning a bare value from a function whose signature promises a Result causes a type error. Wrap success values in Ok(...) and failures in Err(...).
Mixing error types in one chain blocks compilation. Convert them with map_err, or use a shared error type.
Practice Ideas
- Write a function that parses an age and returns an error for negative numbers.
- Build a temperature converter that rejects values below absolute zero.
- Combine two parse steps with
and_thenand print each outcome.
Reading Compiler Guidance
The compiler explains Result mistakes in plain language. Messages such as "mismatched types" usually mean a branch returns a bare value where an Ok wrapper belongs. Follow the arrow in the message to the exact line, and fix the wrapper first. Most Result errors disappear after that single change.
Key Points
- Result has two variants:
Okfor success andErrfor failure. - Handle both variants with
matchor helper methods. - The compiler warns about ignored results.
- Use
map,map_err, andand_thento build clean pipelines.
