期权类型和早期收益。 is_none()时返回错误

时间:2019-03-22 21:04:00

标签: rust

使用匹配(例如在bar中)似乎是一种常见的方法。

#[derive(Debug)]
pub enum MyErrors {
    SomeError,
}

fn foo(x: Option<u64>) -> Result<u64, MyErrors> {
    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<u64>) -> Result<u64, MyErrors> {
    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));
}

但是,早期返回(例如foo中的返回)显着减少了嵌套代码的外观。如果多次必须解开选项或返回错误,则bar之类的代码会非常嵌套...

在空选项情况下尽早返回错误的建议做法是什么?

1 个答案:

答案 0 :(得分:6)

如果由于内部复杂的逻辑而不希望使用更长的方法链,那么仍然有一些可读性低的缩进选项。

ok_or?

我们可以将Option转换为具有所需错误的Result,然后立即使用?运算符对其进行拆包。此解决方案可能提供最小的缩进,并且可以轻松地用于“解包”多个Option

fn bar1(x: Option<u64>) -> Result<u64, MyErrors> {
    let x = x.ok_or(MyErrors::SomeError)?;
    // A lot of stuff going on.
    Ok(x * 2)
}

这将评估ok_or中的错误,无论是否实际使用该错误。如果此计算昂贵,则ok_or_else(会延迟产生错误)将更有效(related question)。

if let

如果嵌套,此解决方案仍然会导致代码阶梯,但是如果更多地使用else分支逻辑,则可能更合适。

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)
    }
}