Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

error handling - Idiomatic way to return Err if an Option is Some

We can use or_else and ? to return Err early if we encounter None:

let o = None;
let x = o.ok_or(666)?;

But what if we expect the opposite? Return early if something is Some:

let o = Some(42);
if o.is_some() {
    return Err(666);
}

Can we somehow do this with ? as well?

question from:https://stackoverflow.com/questions/65864876/idiomatic-way-to-return-err-if-an-option-is-some

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I assume this is all about having it be a single line and saving characters.

You could use map_or(), to convert Some(_) into Err(666) and None into Ok(()). However, this isn't idiomatic, I'd also personally stick to if is_some() { return Err(666); }, as what that is doing is more clear to the reader.

fn foo(o: Option<i32>) -> Result<(), i32> {
    o.map_or(Ok(()), |_| Err(666))?;

    Ok(())
}

fn main() {
    println!("{:?}", foo(None));
    println!("{:?}", foo(Some(42)));
}

Outputs:

Ok(())  
Err(666)

You could also create your own ErrOnSome trait. Naming the method e.g. err_on_some() it would be more clear and assumable to the reader what's going on, even without knowing the implementation of the err_on_some() method.

trait ErrOnSome {
    fn err_on_some<F, E>(&self, f: F) -> Result<(), E>
    where
        F: FnOnce() -> Result<(), E>;
}

impl<T> ErrOnSome for Option<T> {
    fn err_on_some<F, E>(&self, f: F) -> Result<(), E>
    where
        F: FnOnce() -> Result<(), E>,
    {
        match self {
            None => Ok(()),
            Some(_) => f(),
        }
    }
}

fn foo(o: Option<i32>) -> Result<(), i32> {
    o.err_on_some(|| Err(666))?;

    Ok(())
}

Using the same main() it produces the same output of course.


Edit: Old answer - I misread and thought it was about returning Option

If the contained value is a primitive, i.e. cheap to create, then you could stick to xor(). However, this isn't idiomatic, I'd also personally stick to if is_some() { return Err(666); }, as what that is doing is more clear to the reader.

fn foo(o: Option<i32>) -> Option<()> {
    o.xor(Some(666))?;

    Some(())
}

fn main() {
    println!("{:?}", foo(None));
    println!("{:?}", foo(Some(42)));
}

Outputs:

Some(123)
None

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
...