use std::error::Error;
// Pattern 1: Libraries use typed errors, apps use anyhow/Box
type AppResult = Result>;
// Pattern 2: Early return with ?
fn process_data(input: &str) -> AppResult> {
let numbers: Result, _> = input
.lines()
.filter(|l| !l.trim().is_empty())
.map(|l| l.trim().parse::())
.collect();
Ok(numbers?)
}
// Pattern 3: Error context (with anyhow)
// use anyhow::{Context, Result};
// fn read_config(path: &str) -> Result {
// let content = fs::read_to_string(path)
// .with_context(|| format!("Failed to read config from {}", path))?;
// Ok(content.parse()?)
// }
// Pattern 4: Converting errors at boundaries
fn convert_and_log(result: Result) -> Option {
result.map_err(|e| eprintln!("Warning: {}", e)).ok()
}
// Pattern 5: Combining multiple Results
fn multi_parse(a: &str, b: &str, c: &str) -> Result<(i32, f64, bool), String> {
let x = a.parse::().map_err(|e| e.to_string())?;
let y = b.parse::().map_err(|e| e.to_string())?;
let z = c.parse::().map_err(|e| e.to_string())?;
Ok((x, y, z))
}
fn main() {
println!("{:?}", process_data("1
2
3
4
5"));
println!("{:?}", multi_parse("42", "3.14", "true"));
println!("{:?}", multi_parse("oops", "3.14", "true")); // Err on first fail
}