【问题标题】:Idiomatic way to return Err if an Option is Some如果 Option 是 Some,则返回 Err 的惯用方式
【发布时间】:2021-01-23 21:58:40
【问题描述】:

如果遇到None,我们可以使用or_else?提前返回Err

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

但是如果我们期望相反呢?如果是Some,请尽早返回:

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

我们也可以用? 做到这一点吗?

【问题讨论】:

  • afaik 除了使用 if/match 语句之外,还有其他方法可以做到这一点。

标签: error-handling rust optional


【解决方案1】:

我认为这就是让它成为单行并保存字符。

您可以使用map_or(),将Some(_) 转换为Err(666),将None 转换为Ok(())。但是,这不是惯用的,我个人也会坚持if is_some() { return Err(666); },因为这对读者来说更清楚。

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

    Ok(())
}

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

输出:

Ok(())  
Err(666)

您还可以创建自己的 ErrOnSome 特征。命名方法,例如err_on_some() 即使不知道 err_on_some() 方法的实现,读者也会更加清楚和假设发生了什么。

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

使用相同的main() 当然会产生相同的输出。


编辑:旧答案 - 我误读并认为这是关于返回 Option

如果包含的值是一个原始值,即创建的成本很低,那么您可以坚持使用xor()。但是,这不是惯用的,我个人也会坚持使用if is_some() { return Err(666); },因为这对读者来说更清楚。

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

    Some(())
}

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

输出:

Some(123)
None

【讨论】:

    【解决方案2】:

    我们能否以某种方式[在Some 上返回Err] 和?

    我不会称之为惯用,但您可以使用Option::map 将选项的Some 变体映射到Err。这会将Option&lt;T&gt; 转换为Option&lt;Result&lt;X, E&gt;&gt;,因此您需要将其转换为Result&lt;Option&lt;X&gt;, E&gt; 并在其上使用?

    fn x() -> Result<(), i32> {
        let o = Some(42);
        o.map(|_| Err::<(), _>(666)).transpose()?;
        Ok(())
    }
    

    Err 上的 turbofish 提供了必要的类型提示,因为否则 Rust 无法确定上面提到的 Result&lt;X, E&gt;X,结果必须同时具有 ok 和 error 类型。我选择了(),但它与函数返回类型中的()完全无关;它可能是任何其他类型,因为 ? 运算符只关心 Result 的错误类型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-12
      • 2021-07-04
      • 1970-01-01
      • 2013-06-15
      • 1970-01-01
      • 2013-05-21
      • 2018-10-22
      • 1970-01-01
      相关资源
      最近更新 更多