如何在Ok时解包Result,或者在Err时从函数返回?

44

我有一个调用另一个函数的函数,它返回一个 Result。我需要检查这个 Result 是否为 OkErr,如果是 Err,我需要从我的函数中提前 return。目前我正在做的是:

match callable(&mut param) {
    Ok(_v) => (),
    Err(_e) => return,
};

有没有更符合 Rust 语言习惯的方法来完成这个任务?


1
请参见在循环中取消包装或继续执行 - Shepmaster
4个回答

30
您可以创建一个宏:
macro_rules! unwrap_or_return {
    ( $e:expr ) => {
        match $e {
            Ok(x) => x,
            Err(_) => return,
        }
    }
}

fn callable(param: &mut i32) -> Result<i32, ()> {
    Ok(*param)
}

fn main() {
    let mut param = 0;
    let res = unwrap_or_return!(callable(&mut param));

    println!("{:?}", res);
}

请注意,我不建议丢弃错误。Rust的错误处理非常人性化,因此即使只是为了记录错误,我也会返回该错误:

fn callable(param: &mut i32) -> Result<i32, ()> {
    Ok(*param)
}

fn run() -> Result<(), ()> {
    let mut param = 0;
    let res = callable(&mut param)?;

    println!("{:?}", res);

    Ok(())
}

fn main() {
    if let Err(()) = run() {
        println!("Oops, something went wrong!");
    }
}

谢谢。我还修改了您的宏,以允许调用者指定是return还是continue。这在Rust中是否通俗易懂? - Josh Abraham
你在这里创建的宏和 ? 运算符有什么区别? - Paul Razvan Berg
1
@Raul ? 运算符只能在返回 Try 实现者的函数中使用。OP 想要从一个返回 unit 的函数中返回,而 unit 并没有实现 Try - Boiethios
1
通过添加返回Resultrun(),增加间接性是一个好主意,原因有两个:1)在run()内部,您可以使用?来处理错误返回;2)然后您可以在单个位置记录/处理所有错误返回。在我看来,这比创建宏更好。 - user1783732
@user1783732 主函数/运行函数已经过时了:现在,主函数可以返回一个结果。 - Boiethios
1
@Boiethios 没关系。main()是否能返回结果并不重要。我的观点是:当函数foo返回(),而我们仍然想使用?在foo内部进行早期返回时,最好添加一层bar() -> Result(),其中包括允许?早期返回的实际代码,然后foo将调用bar并记录错误。 - user1783732

27

Rust 1.65.0 已经稳定支持 let-else 语句,它使您能够编写以下代码:

let Ok(_v) = callable(&mut param) else { return };

4
这是我处理 Option<T> 的常用方法,因为我知道我的 else 块实际上没有任何操作。但对于 Result<O, Error>,我使用 OP 的方法,因为我想在将其返回之前记录错误对象到日志中。 - Fred Drake

4
如果两个函数都返回Result<doesn't matter, same T>,你只需要在调用行的末尾加上一个?
fn caller() -> Result<Str, i32> {
    let number = job()?; // <-- if job return error this function return/end here 
                         // otherwise the value of Ok will assign to number 
    Ok(format!("the number is {}", number))
}

fn job() -> Result<i32, i32> {
    // do something
    Err(3)
}

你也可以使用同样的模式来处理 Option<T>

2
从 OP 的示例代码中可以很清楚地看出这不是情况:Err(_e) => return, - Shepmaster
虽然这不是上面问题的答案,但我记得有类似的语法,只是具体是什么我一直找不到,直到现在才找到。所以感谢你的回答! - Prophet Lamb

2
您可以使用我的 unwrap_or crate 来完成此操作。
您可以执行:
unwrap_or_ok!(callable(&mut param), _, return);

如果你想要结果并返回错误,你可以这样做:
let v = unwrap_or_ok!(callable(&mut param), error, return error);

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