处理/解开嵌套结果类型的惯用方式是什么? [英] What is the idiomatic way to handle/unwrap nested Result types?

查看:76
本文介绍了处理/解开嵌套结果类型的惯用方式是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我读到在 Result 上使用 unwrap 在Rust中不是一个好习惯,最好使用模式匹配,因此可以适当地处理发生的任何错误。

I read that using unwrap on a Result is not a good practice in Rust and that it's better to use pattern matching so any error that occurred can be handled appropriately.

我明白了,但是考虑这个片段,它读取目录并打印每个条目的访问时间:

I get the point, but consider this snippet that reads a directory and prints the accessed time for each entry:

use std::fs;
use std::path::Path;

fn main() {
    let path = Path::new(".");
    match fs::read_dir(&path) {
        Ok(entries) => {
            for entry in entries {
                match entry {
                    Ok(ent) => {
                        match ent.metadata() {
                            Ok(meta) => {
                                match meta.accessed() {
                                    Ok(time) => {
                                        println!("{:?}", time);
                                    },
                                    Err(_) => panic!("will be handled")
                                }
                            },
                            Err(_) => panic!("will be handled")
                        }
                    },
                    Err(_) => panic!("will be handled")
                }
            }
        },
        Err(_) => panic!("will be handled")
    }
}

我要来处理上面代码中的所有可能错误( panic 宏只是一个占位符)。虽然上面的代码有效,但我认为它很丑。

I want to handle every possible error in the code above (the panic macro is just a placeholder). While the code above works, I think it's ugly. What is the idiomatic way to handle a case like this?

推荐答案


我使用 解包 关于结果在Rust中不是一个好习惯。

I read that using unwrap on a Result is not a good practice in Rust.

这不是那么容易。例如,在在这里我的答案以了解多一点。现在是您的主要问题:

It's not that easy. For example, read my answer here to learn a bit more. Now to your main problem:

代码的一个大问题是正确的移位:例如, meta.accessed()调用缩进了很多。我们可以通过在匹配项中传递要使用的值来避免这种情况:

One big issue with your code is the right shift: for example, the meta.accessed() call is indented a whole lot. We can avoid this by passing the value we want to work with out of the match:

let entries = match fs::read_dir(&path) {
    Ok(entries) => entries, // "return" from match
    Err(_) => panic!("will be handled"),
};

for entry in entries {  // no indentation! :)
    // ...
}

已经很不错了

您的函数可以返回 Result< _,_> 类型,以便将错误传递给调用函数(是,甚至 main()可以返回结果 )。在这种情况下,您可以使用运算符:

Your function could return a Result<_, _> type in order to pass the error to the calling function (yes, even main() can return Result). In this case you can use the ? operator:

use std::{fs, io};

fn main() -> io::Result<()> {
    for entry in fs::read_dir(".")? {
        println!("{:?}", entry?.metadata()?.accessed()?);
    }
    Ok(())
}



使用帮助器结果

的方法

也有很多辅助方法,例如 map() and_then() ,用于结果类型。 and_then 如果您想做某事,如果结果是 Ok ,这会很有帮助,这将返回相同的类型。这是带有 and_then()并手动处理错误的代码:

Use helper methods of Result

There are also many helper methods, like map() or and_then(), for the Result type. and_then is helpful if you want to do something, if the result is Ok and this something will return a result of the same type. Here is your code with and_then() and manual handling of the error:

fn main() {
    let path = Path::new(".");
    let result = fs::read_dir(&path).and_then(|entries| {
        for entry in entries {
            let time = entry?.metadata()?.accessed()?;
            println!("{:?}", time);
        }
        Ok(())
    });

    if let Err(e) = result {
        panic!("will be handled");
    }
}






确实不仅只有一种方法可以进行这种错误处理。您必须了解所有可以使用的工具,然后需要根据情况选择最佳工具。但是,在大多数情况下,运算符是正确的工具。


There really isn't only one way to do this kind of error handling. You have to get to know all the tools you can use and then need to choose the best for your situation. However, in most situations, the ? operator is the right tool.

这篇关于处理/解开嵌套结果类型的惯用方式是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆