Option<T>: Null Safety
fn find_index(haystack: &[i32], needle: i32) -> Option {
haystack.iter().position(|&x| x == needle)
}
fn safe_divide(a: f64, b: f64) -> Option {
if b == 0.0 { None } else { Some(a / b) }
}
fn main() {
let v = vec![10, 20, 30, 40, 50];
// match
match find_index(&v, 30) {
Some(i) => println!("Found at {}", i),
None => println!("Not found"),
}
// if let (cleaner for single case)
if let Some(i) = find_index(&v, 50) {
println!("50 is at index {}", i);
}
// unwrap_or, map, and_then
let result = safe_divide(10.0, 0.0).unwrap_or(f64::INFINITY);
println!("{}", result); // inf
let doubled = safe_divide(10.0, 2.0)
.map(|x| x * 2.0)
.filter(|&x| x > 5.0)
.unwrap_or(0.0);
println!("{}", doubled); // 10.0
// ? operator in Option-returning functions
fn first_doubled(v: &[i32]) -> Option {
Some(v.first()? * 2)
}
println!("{:?}", first_doubled(&[5, 10])); // Some(10)
println!("{:?}", first_doubled(&[])); // None
} Result<T, E>: Recoverable Errors
use std::num::ParseIntError;
fn parse_positive(s: &str) -> Result {
let n: i32 = s.trim().parse()
.map_err(|e: ParseIntError| e.to_string())?;
if n < 0 {
Err(format!("{} is negative", n))
} else {
Ok(n as u32)
}
}
fn main() {
let inputs = ["42", "-5", "abc", "100"];
for s in &inputs {
match parse_positive(s) {
Ok(n) => println!("{} -> Ok({})", s, n),
Err(e) => println!("{} -> Err({})", s, e),
}
}
// map, and_then, unwrap_or_else
let doubled: Result = parse_positive("21").map(|n| n * 2);
println!("{:?}", doubled); // Ok(42)
// Convert Result to Option
let opt: Option = parse_positive("5").ok();
let res: Result = opt.ok_or("was None");
println!("{:?} {:?}", opt, res);
} 🎯 Practice
- Write fn safe_sqrt(x: f64) -> Option<f64> - None if x < 0
- Write fn parse_range(s: &str) -> Result<(i32,i32), String> parsing "10..20" format
- Chain: parse a string to f64, take sqrt (Option), convert to Result, and_then check it is > 1
🎉 Key Takeaways
- Option<T> replaces null - forces explicit None handling
- Result<T,E> represents fallible operations with typed errors
- map, and_then, filter, unwrap_or all work on both types
- ? operator propagates None/Err up the call stack