I tried to switch from match to let-else for my error handling, but not having access to the value in the else block severely limits what you can do: I can't log the error, convert it, or match on it.
Things are a bit better with Option, since with None you don't have a value. Still, I try to stick with match for consistency, as alongside you would often have matches on Results, and being consistent is more important than saving a few keystrokes.
While let-else is occasionally useful, the feature often feels underwhelming.
Not saying it isn't useful for others—just sharing my thoughts.
I assume you are actually talking about if let with optional else ? My understanding was always, that for the case that an else or even an else if is required, a match is the better alternative. See if let - Rust By Example
I wasn't sure what to make of it at first, too, but I've grown to like it and now I use it surprisingly often in cases where control flow diverges. For handling Result types I don't use it as frequently, mostly sticking to ? or actually handling the error.
It depends a lot on what I need to do with either part of the result, so
whether there's an actual value in Ok and in Err or not, and
whether the scope itself returns a Result / Option and supports ? or if it needs to be processed in place.
When I need to process both, I also usually prefer the match to let-else and methods that split the content. It leaves enough room to write the code for both alternatives and it's easier to read. But if there's a lot of code remaining for the Ok and the Err is anecdotical, I may prefer the if-else. Or even expect if the error is not supposed to happen or can't happen per design.
I like to use it in early-return scenarios to check some preconditions of the input. Something akin to assert!. Combining this with unwrapping a value at the same time is quite convenient I must admit. Example.
I meant that, in case the error can be transferred with ? (or map_err(...)?), there's no need for an else or a match. For me, there isn't a generic pattern suitable for all situations.
It's a shortcut syntax for an extremely common thing in Rust: "give me a value when this pattern matches, and otherwise do this thing regardless of value." When you don't meet those criteria, then use a match. I don't really get the problem here.
Alternative syntaxes, including ones where else is not diverging or where you can match in the else block, were considered: 3137-let-else - The Rust RFC Book
I thought about this a bit more, and the main problem that I have is that let-else makes it very hard to pass around context on why errors are happening, and I am always trying to improve my errors to be as far away from file not found C-style error messages as possible, which, I feel like, let-else is in direct conflict with.
Don't use let-else when you need to handle errors. It's only for cases where you don't need the error (or in the case of Option<T> values, for example, when there is no error).
I'd focus on the some part of the quote. Because the next paragraph goes on to say (my emphasis):
if-let expressions offer a succinct syntax for pattern matching single patterns. This is particularly useful for unwrapping types like Option, particularly those with a clear “success” variant for the given context but no specific “failure” variant.
The "no specific failure variant" part seems to me to be the crux of this topic.
Also from the RFC:
let-else is particularly useful when dealing with enums which are not Option/Result, and as such do not have access to e.g. ok_or().
As others said before, I don't use let-else to handle results.
For me, let-else is a way to reduce right drift due to nested blocks, since it makes the value accesible, opposed to if-let-else. So I use let-else only with Option.
For results, I often have
let x = result.inspect_err()?;
Note that there is no inspect_err for Option.