โข Option
โข Result
โข The ? operator propagates errors up the call stack concisely
โข Combinators like .map(), .and_then(), .unwrap_or() chain fallible operations
โข The compiler forces you to handle every error case โ no silent failures
โข Option
โข Result
โข The ? operator propagates errors up the call stack concisely
โข Combinators like .map(), .and_then(), .unwrap_or() chain fallible operations
โข The compiler forces you to handle every error case โ no silent failures
fn safe_div(a: i32, b: i32) -> Option<i32> {
if b == 0 { None } else { Some(a / b) }
}
fn safe_sqrt(x: f64) -> Option<f64> {
if x < 0.0 { None } else { Some(x.sqrt()) }
}
// Combinator chain โ None propagates through automatically
fn compute(a: i32, b: i32) -> Option<f64> {
safe_div(a, b)
.map(|q| q as f64) // transform if Some
.and_then(safe_sqrt) // chain another fallible operation
.map(|r| r * 2.0) // transform the result
}
// filter_map โ transform + filter in one pass
let names: Vec<Option<&str>> = vec![Some("alice"), None, Some("bob")];
let upper: Vec<_> = names.iter()
.filter_map(|o| o.map(str::to_uppercase))
.collect(); // ["ALICE", "BOB"] โ None silently dropped
// Fallback values
let x: Option<i32> = None;
x.unwrap_or(0); // 0 โ cheap default
x.unwrap_or_else(|| 42); // 42 โ computed lazily
x.unwrap_or_default(); // 0 โ T's Default::default()
// and_then for chained fallible ops
let parsed = Some("42")
.and_then(|s| s.parse::<i32>().ok()) // parse may fail
.filter(|&n| n > 0); // discard negatives
// flatten, zip
Some(Some(42)).flatten(); // Some(42) โ remove one Option layer
Some(1).zip(Some("hello")); // Some((1, "hello"))
Some(1).zip(None::<&str>); // None
| Concept | OCaml | Rust | ||
|---|---|---|---|---|
| Type | `'a option` | `Option<T>` | ||
| Variants | `Some x`, `None` | `Some(x)`, `None` | ||
| Map | `Option.map f opt` | `opt.map(\ | x\ | f(x))` |
| Chain/bind | `Option.bind opt f` or `let*` | `opt.and_then(f)` | ||
| Filter | `Option.filter f opt` | `opt.filter(pred)` | ||
| Default | `Option.value opt ~default` | `opt.unwrap_or(default)` |
fn safe_div(a: i32, b: i32) -> Option<i32> { if b==0 {None} else {Some(a/b)} }
fn safe_sqrt(x: f64) -> Option<f64> { if x<0.0{None} else {Some(x.sqrt())} }
fn compute(a: i32, b: i32) -> Option<f64> {
safe_div(a, b).map(|q| q as f64).and_then(safe_sqrt).map(|r| r*2.0)
}
fn main() {
for (a,b) in [(10,2),(10,0),(-4,2)] {
match compute(a,b) {
Some(v) => println!("{}/{} -> {:.2}", a, b, v),
None => println!("{}/{} -> None", a, b),
}
}
let names: Vec<Option<&str>> = vec![Some("alice"),None,Some("bob")];
let upper: Vec<_> = names.iter().filter_map(|o| o.map(str::to_uppercase)).collect();
println!("{:?}", upper);
// Combinators
let x: Option<i32> = None;
println!("unwrap_or: {}", x.unwrap_or(0));
println!("unwrap_or_else: {}", x.unwrap_or_else(|| 42));
println!("unwrap_or_default: {}", x.unwrap_or_default());
let s: Option<&str> = Some("42");
let parsed = s.and_then(|s| s.parse::<i32>().ok());
println!("parsed: {:?}", parsed);
println!("filtered: {:?}", parsed.filter(|&n| n > 0));
// flatten, zip
let nested: Option<Option<i32>> = Some(Some(42));
println!("flatten: {:?}", nested.flatten());
println!("zip: {:?}", Some(1).zip(Some("hello")));
}
#[cfg(test)]
mod tests {
use super::*;
#[test] fn div_ok() { assert_eq!(safe_div(10,2), Some(5)); }
#[test] fn div_zero(){ assert_eq!(safe_div(10,0), None); }
#[test] fn combinator(){
let opt: Option<i32> = Some(4);
assert_eq!(opt.map(|x|x*2), Some(8));
assert_eq!(opt.filter(|&x|x>10), None);
}
}
(* Option idioms in OCaml *)
let (let*) = Option.bind
let safe_div a b = if b=0 then None else Some(a/b)
let safe_sqrt x = if x < 0.0 then None else Some(sqrt x)
let compute a b =
let* q = safe_div a b in
let* r = safe_sqrt (float_of_int q) in
Some (r *. 2.0)
let () =
let show label = function None->Printf.printf "%s: None\n" label
| Some v -> Printf.printf "%s: %.2f\n" label v in
show "10/2" (compute 10 2);
show "10/0" (compute 10 0);
show "-4/2" (compute (-4) 2);
let names = [Some"alice";None;Some"bob"] in
let upper = List.filter_map (Option.map String.capitalize_ascii) names in
List.iter print_endline upper