debugrustMajor
Option types and early returns. return an Error when is_none()
Viewed 0 times
errorreturnreturnsandis_noneoptionwhenearlytypes
Problem
Using match (like in
However, early returns (such as in
What is the recommended practice for early returning an error in the case of empty options?
bar) seems to be a common approach..#[derive(Debug)]
pub enum MyErrors {
SomeError,
}
fn foo(x: Option) -> Result {
if x.is_none() {
return Err(MyErrors::SomeError);
}
// .. some long code where more options
// are checked and matched
// The ok here is just so the code is simple and compiles
Ok(x.unwrap() * 2)
}
fn bar(x: Option) -> Result {
match x {
None => {
return Err(MyErrors::SomeError)?;
}
Some(v) => {
// .. some long code where more options
// are checked and matched
// The ok here is just so the code is simple and compiles
Ok(x.unwrap() * 2)
}
}
}
fn main() {
foo(Some(1));
bar(Some(2));
}However, early returns (such as in
foo) significantly reduce how nested the code looks like. If there are multiple times when an option has to be unwrapped or an error returned, code like bar gets very nested...What is the recommended practice for early returning an error in the case of empty options?
Solution
If a longer method chain is undesirable due to complex logic inside, there are still a few readable, low-indent options.
We can convert an
This will evaluate the error inside
This solution can still lead to a staircase of code if nested, but may be more appropriate if the
ok_or and ?We can convert an
Option to a Result with a desired error, and immediately unwrap it with the ? operator. This solution probably provides the least indent possible, and can be easily used to "unwrap" multiple Options.fn bar1(x: Option) -> Result {
let x = x.ok_or(MyErrors::SomeError)?;
// A lot of stuff going on.
Ok(x * 2)
}This will evaluate the error inside
ok_or regardless of whether or not it will actually be used. If this computation is expensive, ok_or_else, which produces the error lazily, will be more efficient (related question).if letThis solution can still lead to a staircase of code if nested, but may be more appropriate if the
else branch logic is more involved.fn bar2(x: Option) -> Result {
if let Some(x) = x {
// Lot of stuff here as well.
Ok(x * 2)
} else {
Err(MyErrors::SomeError)
}
}Code Snippets
fn bar1(x: Option<u64>) -> Result<u64, MyErrors> {
let x = x.ok_or(MyErrors::SomeError)?;
// A lot of stuff going on.
Ok(x * 2)
}fn bar2(x: Option<u64>) -> Result<u64, MyErrors> {
if let Some(x) = x {
// Lot of stuff here as well.
Ok(x * 2)
} else {
Err(MyErrors::SomeError)
}
}Context
Stack Overflow Q#55307746, score: 73
Revisions (0)
No revisions yet.