当返回类型既不是Option也不是Result时如何替换问号运算符

3
Rust 有一个问号运算符,可以像这样使用:
fn make_foo() -> Option<Foo> { ... }

fn make_bar() -> Option<Bar> {
    let foo = make_foo()?;
    // ... Many lines of code using `foo` to compute data for `Bar::make` ...
    Some(Bar::make(...))
}

但如果我想要一个返回Bar而不是Option<Bar>的函数呢(因此在make_foo()返回None时返回Bar::new而不是None)?

当然,我可以这样做:

fn make_bar() -> Bar {
    match make_foo() {
        None => { Bar::new() }
        Some(foo) => {
            // ... Many lines of code using `foo` to compute data for `Bar::make` ...
            Bar::make(...)
        }
    }
}

但是这会增加整个函数的嵌套级别,我不喜欢这样。我想要一个替代 ? 操作符的方法。

所以我想到了下面这个:

fn make_bar() -> Bar {
    let foo = match make_foo() {
        None => { return Bar::new(); }
        Some(v) => v
    };
    // ... Many lines of code using `foo` to compute data for `Bar::make` ...
    Bar::make(...)
}

这是合乎惯用法的Rust代码吗?还是有更好的解决方案?

2
看起来还不错。不过当let...else稳定下来后,可能会有一种更简洁的方式。 - user3840170
2个回答

3
有多种方法可以做到这一点,我不会说哪一种比另一种更好。但是,让我给你提供另一种选项,如果您在此函数中多次使用 ? 运算符可能会有用。早期有很多 return Bar::new() 很可能会变得老套。使用这种方法,您可以两全其美。 Option 有许多实用方法。您可以在此情况下将 .and_then() 与最终的 .unwrap_or_else() 结合使用。
fn make_bar() -> Bar {
    make_foo()
    .and_then(|foo| {
        // Do stuff with foo
        Some(Bar::make(...))
    })
    .unwrap_or_else(Bar::new)
}

这确实增加了嵌套层级,但只增加了一次,并且有一个优点,您可以在映射函数内部使用?来导致外部函数返回默认的Bar::new()值。
(如果您在Bar上实现了Default,那么您甚至可以在末尾使用更简洁的.unwrap_or_default()。)

我认为在这种情况下,您需要两次“展平”或“解包”。Option<T>::map接受从TU的函数,并返回Option<U>。因此,如果映射器返回一个Option<V>,结果将是Option<Option<V>>,对吗? - Andrei Matveiakin
@AndreiMatveiakin 是的,我经常混淆map和and_then。已修复。 - cdhowie

3

这个 Rust 代码是否合适?

是的,看起来不错。你可以去掉大括号:

let foo = match make_foo() {
    None => return Bar::new(),
    Some(v) => v
};

最好的选择是 let-else(不稳定):
fn make_bar() -> Bar {
    let Some(foo) = match make_foo() else {
        return Bar::new();
    };
    // ... Many lines of code using `foo` to compute data for `Bar::make` ...
    Bar::make(...)
}

查看类似的问题,请参见Rust 中使用早期返回处理错误的惯用方式


注意:自Rust 1.65版本以来稳定。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接