Earlier quoted context omitted.
The idiomatic way to solve that in rust is to re-bind to the same variable name. if let Some(foo) = foo { /* ... * / } That's possible because in Rust name shadowing let foo = grab_foo_bytes(); let foo = parse_foo_bytes(foo); makes the previous binding of the variable no longer namable and thus no longer accessible, but doesn't drop it (and trigger RAII destructors). Now someone will probably come in and say "oh no,…
> The idiomatic way to solve that in rust is to re-bind to the same variable name. OK, that's reasonable. Is the idiomatic way to use optionals to introduce a layer of nesting? I prefer keeping functions very "flat"-looking. It sounds like Rust's optionals will give people an excuse to create labyrinthine functions where I'm constantly scrolling around to remind myself of what level of nesting I'm at and whether I'm…
I definitely agree. One way I do that is by having an internal function that takes a valid value and a public function that does the validating/error handling.
That doesn't always make sense though. There's a few other idiomatic ways to avoid nesting. Since statements evaluate to values, you can write
let foo = if let Some(foo) = foo {
foo
} else {
// Something that either evaluates to the same type as foo or returns early
}
That's so common there's a special operator for it, ?. It essentially either early returns the sad path or evaluates to the happy path. fn get_foo() -> Option;
fn frob() -> Option {
let foo = get_foo()?;
let bar = convert_to_bar(foo);
Some(bar)
}
I prefer to use Result to model missing data like cases instead of Option because it composes better. So that might be fn get_foo() -> Option;
fn frob() -> Result {
let foo = get_foo().ok_or(BarNotFound)?;
let bar = convert_to_bar(foo);
Some(bar)
}
#[derive(Debug, thiserror::Error)]
#[error("Bar not found")]
struct BarNotFound;
That last bit uses a stdlib macro and a very commonly used external lib macro to save a few lines of repetitive typing.Edit: Also ? doesn't special case Result and Option. You can make your own type conform to the interface (trait) it requires. That would probably be weird though.