我读到在unwrap
上使用Result
在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
宏只是一个占位符)。虽然上面的代码有效,但我觉得它很难看。处理这种情况的惯用方法是什么?
答案 0 :(得分:11)
我读到在结果中使用
unwrap
在Rust中不是一个好习惯。
这并不容易。例如,阅读my answer here以了解更多信息。现在你的主要问题是:
Ok
值传递到外部您的代码的一个大问题是正确的转变:例如,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! :)
// ...
}
这已经是使代码更具可读性的一种非常好的方法。
?
运算符将错误传递给调用函数您的函数可以返回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(())
}
Result
Result
类型还有许多辅助方法,如map()
或and_then()
。如果您想要执行某些操作,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");
}
}
确实不仅有一种方式来执行此类错误处理。您必须了解可以使用的所有工具,然后需要根据您的具体情况选择最佳工具。但是,在大多数情况下,?
运算符是正确的工具。
答案 1 :(得分:4)
Result
happens to have a lot of convenience methods对于这些事情:
ng-bind-html
通常你在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.and_then(|e| e.metadata()).map(|m| m.accessed()) {
Ok(time) => {
println!("{:?}", time);
},
Err(_) => panic!("will be handled")
}
}
},
Err(_) => panic!("will be handled")
}
}
中没有那么多逻辑,只能在另一个函数中使用main
或try!
:
?