Except the let-else version has one big disadvantage. The 'match' version has bound the error to `e`, so you can log that error or inspect it. The 'let-else' version can't read the error, so its log message can't be as useful. You can't check if it's a specific error, or include the error in logged messages.
It's still convenient, but in really limited circumstances, AFAICT. This week I'll be going through the various Rust projects I maintain at work, seeing if there's useful places for let-else.
> This week I'll be going through the various Rust projects I maintain at work, seeing if there's useful places for let-else.
If you want help from automation, you can wait a few days until the manual_let_else clippy lint arrives on nightly. It's going to be one of the pedantic lints, and recognizes some obvious places where let else would make sense (not all but many). It should arrive in one week-ish, depending on when the next clippy update is in nightly.
Update: I did go through every `match` statement in my 16k-line Rust project at work, and I found a number of places where it was useful. My commit to use let-else had 10 files changed, 27 insertions(+), 48 deletions(-).
Yes, though that doesn't put the value of the `Ok` variant into any scope. At the end of the day, if you need maximum flexibility for whatever you're doing then you still need to reach for `match`, even if it's a bit more verbose.
I mean, in all cases `if let` is for when there's nothing in other constructors that you want to talk about. That'll be every time you match on `Option<T>`, `Result<T, ()>`, or `Result<(), T>`, all of which come up at least occasionally, and will occasionally be other cases.
Edited to add: I don't mean to imply that you should always use `if let` for those cases - that may be but I reserve judgement on it.
Swift has `guard else`, including `guard let else` for preconditions, where you only put the error responding code and where the compiler forces you to exit the current context (e.g. return a value, throw an error, etc).
It is nice for collapsing pyramids of doom that come from normal precondition checking. You can put multiple comparisons or variable assignments into a a single guard as well, separated by commas.
It does not support binding to the error in a Result though, so for these you usually still get more readable code handling these with try/catch, with the corresponding nested code block.
It's mostly about avoiding nesting. Honestly, I'm still pretty ambivalent about it. But, before you might do:
if let Some(x) = maybe_x {
// do stuff with x
} else {
return;
}
now, you'd do:
let Some(x) = maybe_x else {
return;
}
// do stuff with x
If you have several instances of this kind of thing, the nesting can be pretty ugly and hard to read, so we'd sometimes do janky things to avoid the nesting, like:
let x = if let Some(x) = maybe_x { x } else { return; };
or,
if let (Some(x), Some(y)) = (maybe_x, maybe_y) {
// do stuff with x and y with only one layer of nesting
} else {
return;
}