Wanted to get some opinions on formatting. I have a bunch of functions that return Result<T, String>
and I just realized you can do Err("I am a string literal")?, since the ? does the type conversion implicitly. How do y'all think this compares to using into/to_string/to_owned?
Something I'm probably alone in doing is return Err(_)?;, assuming there is an impl From<InnerErr> for OuterErr.
For the compiler it makes no difference (i.e. the return is never actually used), but it helps human readers while visually scanning for certain code, both because it's closer to the start of the line, and because it's longer and therefore more easily spotted.
This doesn't make the ? useless though, as it's more succinct in converting the error than .map_err(OuterErr::from) or some such.
error[E0308]: `else` clause of `let...else` does not diverge
--> src/main.rs:2:35
|
2 | let Some(x) = None::<u8> else {
| ___________________________________^
3 | | Err("uhoh")?;
4 | | };
| |_____^ expected `!`, found `()`
|
= note: expected type `!`
found unit type `()`
= help: try adding a diverging expression, such as `return` or `panic!(..)`
= help: ...or use `match` instead of `let...else`
But this does work:
let Some(x) = None::<u8> else {
return Err("uhoh")?;
};
because there's a subtle difference between syntactically diverging and only value-/type-level diverging.
Certainly, yes. But if I were to make a macro, say, that I wanted to use like return -- where rustfmt will add a ; -- then including the sortof-unnecessary return would probably be a good idea.
(I don't know this history behind rustfmt thinking that break; and continue; are better than the semicolon-less versions, but in a codebase under its thumb I'd be used to writing diverging things with a semicolon.)
Of course, my point isn’ṯ to argue against that there’s a difference, but instead just to leave a hint for anyone who might actually run into an error like the one you posted, that there’s a shorter way to make it compile than adding a return.
Incidentally, speaking of rustfmt, the
let Some(x) = None::<u8> else {
Err("uhoh")?
};
version get’s nicely compacted into a single line, too:
let Some(x) = None::<u8> else { Err("uhoh")? };
which I’d consider an additional win ^^
Whereas, on the other hand, rustfmtdoes decide to format
let Some(x) = None::<u8> else { return Err("uhoh")? };
back into
let Some(x) = None::<u8> else {
return Err("uhoh")?;
};
adding more lines and more semicolons :-/
Once never type is stable (or using tricks) one could also write Err::<!, _>("uhoh")? which then even works with an additional semicolon.