我读到在Result上使用unwrap并不是一个很好的防 rust 方法,最好使用模式匹配,这样发生的任何错误都可以得到适当的处理.

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

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宏只是一个占位符).虽然上面的代码有效,但我认为它很难看.处理这种情况的惯用方法是什么?

推荐答案

我读到在一个结果上使用unwrap不是一个很好的防 rust 实践.

没那么容易.例如,阅读my answer here以了解更多信息.现在谈谈你的主要问题:


Reduce right shift by passing Ok value to the outside

代码的一个大问题是右移:例如,meta.accessed()调用缩进了很多.我们可以通过从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! :)
    // ...
}

这已经是一种让代码更具可读性的好方法.

Using the ? operator to pass the error to the calling function

您的函数可以返回Result<_, _>类型,以便将错误传递给调用函数(是的,even main() can return Result).在这种情况下,您可以使用?运算符:

use std::{fs, io};

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

Use helper methods of Result

Result类型也有很多辅助方法,比如map()and_then().如果你想做某件事,如果结果是Ok,那么and_then是有用的,这件事将返回相同类型的结果.以下是您的代码和错误的手动处理:

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");
    }
}

这并不是唯一的错误处理方法.你必须了解所有可以使用的工具,然后根据自己的情况 Select 最好的工具.然而,在大多数情况下,?运算符是正确的工具.

Rust相关问答推荐

使用DeliverProcess W或ShellExecuteExW复制Windows Run行为?

如何在Rust中在屏幕中间打印内容?

计算具有相邻调换且没有插入或删除的序列的距离

如何在不安全的代码中初始化枚举 struct

为什么单元类型(空元组)实现了`Extend`trait?

包含嵌套 struct 的CSV

如何使用字符串迭代器执行查找?

如何正确地将App handler传递给Tauri中的其他模块?

在自定义序列化程序中复制serde(With)的行为

如何在递归数据 struct 中移动所有权时变异引用?

为什么';t std::cell::ref使用引用而不是非空?

当发送方分配给静态时,Tokio MPSC关闭通道

rust 蚀生命周期 不匹配-不一定超过此处定义的生命周期

Rust ndarray:如何从索引中 Select 数组的行

当锁被释放时,将锁包装到作用域中是否会发生变化?

Rust中的标记特征是什么?

Rust typestate 模式:实现多个状态?

火箭整流罩、tokio-scheduler 和 cron 的生命周期问题

编写 TOML 文件以反序列化为 struct 中的枚举

加入动态数量的期货