-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Closed
Labels
A-lintArea: New lintsArea: New lints
Description
What it does
I sometimes see return Err(MyError::SomeError(v))?;
-- which seems redundant - it has both the return
AND the question mark operator. So this can be rewritten as either
Err(MyError::SomeError(v))?;
- without the returnreturn Err(MyError::SomeError(v));
- without the question operator
The second option only works if the error type is the same as in Result<..., MyError>
, otherwise it only works with the question mark.
So question - does it make sense to suggest needless return
in the case where it can be expressed with a question mark? Or should the question mark be suggested to be removed in the case where it can? Or neither?
Advantage
- shorter code - no confusion over two "return" operators
Drawbacks
- without
return
might be less readable, so perhaps only for same-result-errors and remove the question mark?
Example
use thiserror::Error;
#[derive(Error, Debug)]
enum MyTopError {
#[error("Internal Error: {0}")]
SubError(#[from] MySubError),
#[error("Main Error")]
MainError,
}
#[derive(Error, Debug)]
enum MySubError {
#[error("Value {0} too small")]
TooSmall(i32),
}
fn foo(v: i32) -> Result<(), MyTopError> {
if v < 5 {
return Err(MySubError::TooSmall(v))?;
// This is identical to the above, but too verbose:
// return Err(MyTopError::SubError(MySubError::TooSmall(v)));
// This is identical to the above, but has no "return"
// Err(MySubError::TooSmall(v))?;
// This causes an error: mismatched types
// return Err(MySubError::TooSmall(v));
}
if v > 100 {
return Err(MyTopError::MainError)?;
// Err(MyTopError::MainError)?; // This is identical to the above, but has no "return"
// return Err(MyTopError::MainError); // This is identical to the above, but has no question mark
}
println!("v: {v}");
Ok(())
}
fn main() {
let v = 3;
let r = foo(v);
println!("r: {:?}", r);
}
Centri3
Metadata
Metadata
Assignees
Labels
A-lintArea: New lintsArea: New lints