rust 如果选项为Some,则返回Err的惯用方法

rwqw0loc  于 2023-03-08  发布在  其他
关注(0)|答案(2)|浏览(228)

如果遇到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);
}

我们能用?也做到这一点吗?

czfnxgou

czfnxgou1#

我想这一切都是为了让它成为单行并节省字符。
你可以使用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 trait,把这个方法命名为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

如果包含的值是一个原语,即 * create * 便宜,那么你可以坚持使用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
qojgxg4l

qojgxg4l2#

我们是否可以用某种方法[在Some上返回Err]同时返回?
我不会称之为 idiomatic,但是你可以使用Option::map将选项的Some变体Map为Err,这会将Option<T>转换为Option<Result<X, E>>,你可以将其转换为Result<Option<X>, E>,然后使用?

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

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

相关问题