handle/unwrap 嵌套结果类型的惯用方法是什么?
What is the idiomatic way to handle/unwrap nested Result types?
我读到在 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
宏只是一个占位符)。虽然上面的代码有效,但我认为它很丑陋。处理这种情况的惯用方法是什么?
Result
happens to have a lot of convenience methods 对于这些事情:
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!
:
use std::fs;
use std::path::Path;
fn print_filetimes(path: &Path) -> Result<(), std::io::Error> {
for entry in fs::read_dir(&path)? {
let time = entry.and_then(|e| e.metadata()).map(|m| m.accessed())?;
println!("{:?}", time);
}
Ok(())
}
fn main() {
let path = Path::new(".");
match print_filetimes(path) {
Ok(()) => (),
Err(_) => panic!("will be handled"),
}
}
I read that using unwrap
on a Result is not a good practice in Rust.
没那么容易。例如,阅读 以了解更多信息。现在解决您的主要问题:
通过向外部传递 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! :)
// ...
}
这已经是提高代码可读性的好方法了。
使用 ?
运算符将错误传递给调用函数
您的函数可以 return 一个 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()
or and_then()
。如果你想做某事,and_then
很有用,如果结果是 Ok
并且这个东西将 return 是相同类型的结果。这是带有 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");
}
}
确实不止 一种 方法可以进行这种错误处理。您必须了解所有可以使用的工具,然后需要选择最适合您情况的工具。但是,在大多数情况下,?
运算符是正确的工具。
我读到在 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
宏只是一个占位符)。虽然上面的代码有效,但我认为它很丑陋。处理这种情况的惯用方法是什么?
Result
happens to have a lot of convenience methods 对于这些事情:
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!
:
use std::fs;
use std::path::Path;
fn print_filetimes(path: &Path) -> Result<(), std::io::Error> {
for entry in fs::read_dir(&path)? {
let time = entry.and_then(|e| e.metadata()).map(|m| m.accessed())?;
println!("{:?}", time);
}
Ok(())
}
fn main() {
let path = Path::new(".");
match print_filetimes(path) {
Ok(()) => (),
Err(_) => panic!("will be handled"),
}
}
I read that using
unwrap
on a Result is not a good practice in Rust.
没那么容易。例如,阅读
通过向外部传递 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! :)
// ...
}
这已经是提高代码可读性的好方法了。
使用 ?
运算符将错误传递给调用函数
您的函数可以 return 一个 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()
or and_then()
。如果你想做某事,and_then
很有用,如果结果是 Ok
并且这个东西将 return 是相同类型的结果。这是带有 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");
}
}
确实不止 一种 方法可以进行这种错误处理。您必须了解所有可以使用的工具,然后需要选择最适合您情况的工具。但是,在大多数情况下,?
运算符是正确的工具。