Option<T> and Result<T, E> in Depth
Result<T, E> Combinators
Result<T, E> provides a symmetric suite of combinators that transform either the success track (Ok(T)) or the failure track (Err(E)), chain fallible steps, or recover from errors without verbose match expressions.
Overview of Result<T, E> Combinators
Success Track (`Ok(T)`): ── .map(f) ──────> Ok(f(T))
── .and_then(g) ─> g(T) -> Result<U, E>
│
Failure Track (`Err(E)`): ── .map_err(h) ──> Err(h(E))
── .or_else(r) ──> r(E) -> Result<T, F>
| Combinator | Acts On | Leaves Unchanged | Closure / Argument Signature | Return Type |
|---|---|---|---|---|
res.map(f) |
Ok(T) |
Err(E) |
FnOnce(T) -> U |
Result<U, E> |
res.map_err(f) |
Err(E) |
Ok(T) |
FnOnce(E) -> F |
Result<T, F> |
res.and_then(f) |
Ok(T) |
Err(E) |
FnOnce(T) -> Result<U, E> |
Result<U, E> |
res.or_else(f) |
Err(E) |
Ok(T) |
FnOnce(E) -> Result<T, F> |
Result<T, F> |
res.and(res_b) |
Ok(T) |
Err(E) |
Result<U, E> |
Result<U, E> |
res.or(res_b) |
Err(E) |
Ok(T) |
Result<T, F> |
Result<T, F> |
res.unwrap_or_else(f) |
Err(E) |
Unwraps Ok(T) |
FnOnce(E) -> T |
T |
Chaining .and_then() and Recovering with .or_else()
.and_then(f)runs the next fallible stepf(val)only if the current result isOk(val)..or_else(f)attempts a fallback recovery operationf(err)only if the current result isErr(err):
fn parse_port(raw: &str) -> Result<u16, String> {
raw.trim()
.parse::<u16>()
.map_err(|e| format!("parse error: {e}"))
.and_then(|port| {
if port >= 1024 {
Ok(port)
} else {
Err(format!("port {port} is privileged (< 1024)"))
}
})
}
fn resolve_port(primary: &str, fallback: &str) -> Result<u16, String> {
// If `primary` fails, `.or_else()` attempts `fallback`:
parse_port(primary).or_else(|_primary_err| parse_port(fallback))
}
fn main() {
println!("Primary valid: {:?}", resolve_port("8080", "9000"));
println!("Fallback used: {:?}", resolve_port("80", "9000"));
println!("Both invalid: {:?}", resolve_port("bad", "22"));
}
Primary valid: Ok(8080)
Fallback used: Ok(9000)
Both invalid: Err("port 22 is privileged (< 1024)")
Querying Result Predicates (is_ok_and and is_err_and)
In addition to .is_ok() and .is_err(), res.is_ok_and(f) and res.is_err_and(f) test both the variant and an inner predicate in one call:
fn main() {
let ok_val: Result<i32, &str> = Ok(42);
let err_val: Result<i32, &str> = Err("timeout");
println!("Ok and > 20: {}", ok_val.is_ok_and(|x| x > 20));
println!("Err is 'timeout': {}", err_val.is_err_and(|e| e == "timeout"));
}
Ok and > 20: true
Err is 'timeout': true