In Rust, the Option and Result types are really common. Here are a few idioms I've discovered for working with them using combinators which can simplify code:
// Our program needs a string for something (e.g. filename, database table name, etc).
// To start, we can get this as an optional string - here a CLI argument, but it could be anything; e.g.
// a value parsed from JSON, etc. The `.nth(1)` call here gives us an `Option<String>`.
// We want to compute a fallback value, but doing so can fail (e.g. return `Result<String>`).
// Here's the trick - we use `.map(Ok)` to convert our `Option<String>` to `Option<Result<String>>`,
// which means the type signature works for `.unwrap_or_else()`, giving us in the end a Result<String>,
// on which we can use the regular `?` operator.
let v: String = std::env::args()
.nth(1)
.map(Ok)
.unwrap_or_else(|| std::fs::read_to_string("/etc/someconfig.conf"))?;
// We start with an optional string (but this could be any Option<T>).
// We want to perform a falliable operation on it, giving us an Option<Result<T>>;
// here T is u64 - we're just parsing the string. But, this could e.g. be loading
// the file contents with that name, looking up a value in a database, etc.
// The `transpose()` method swaps that to `Result<Option<T>>
// on which we can use the regular `?` operator, ending up with our mapped/processed value.
let v: Option<u64> = std::env::args()
.nth(1)
.map(|o| o.parse::<u64>())
.transpose()?;