为什么试试!()和? 在main中使用时不能编译?

为什么这个代码不能编译?

use std::io; use std::fs; use std::path::Path; fn main() { // Open path let dir = Path::new("../FileSystem"); // Check if it is a directory if !dir.is_dir() { println!("Is not a directory"); return; } for item in try!(fs::read_dir(dir)) { let file = match item { Err(e) => { println!("Error: {}", e); return; } Ok(f) => f, }; println!(""); } println!("Done"); } 

这是我得到的错误

 error[E0308]: mismatched types --> src/main.rs:15:17 | 15 | for item in try!(fs::read_dir(dir)) { | ^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `std::result::Result` | = note: expected type `()` found type `std::result::Result<_, _>` = help: here are some functions which might fulfill your needs: - .unwrap() - .unwrap_err() - .unwrap_or_default() = note: this error originates in a macro outside of the current crate 

我认为这是抱怨这一行: for item in try!(fs::read_dir(dir))

我也试过这个问号运算符:

 for item in fs::read_dir(dir)? { 

其中有一个不同的错误:

 error[E0277]: the trait bound `(): std::ops::Try` is not satisfied --> src/main.rs:15:17 | 15 | for item in fs::read_dir(dir)? { | ------------------ | | | the `?` operator can only be used in a function that returns `Result` (or another type that implements `std::ops::Try`) | in this macro invocation | = help: the trait `std::ops::Try` is not implemented for `()` = note: required by `std::ops::Try::from_error` 

之前版本的Rust对std::ops::Carrier有类似的错误

我应该避免try!()? ? 什么是处理错误的最好方法? 大多数情况下我是这样做的:

 match error_prone { Err(e) => { println!("Error: {}", e); return; }, Ok(f) => f, }; 

但是,如果我不得不在循环中使用它,这是一个完整的混乱

 for i in match error_prone { // match code } { // loop code } 

try! 是一个自动返回Err的macros; ? 是做同样的事情的语法。 两者只能在返回Result函数中使用(直到实现RFC 1859 )。 main不返回任何值(直到RFC 1937被实现)。

这是如何转换你的代码使用?

 use std::error::Error; use std::fs; use std::path::Path; fn print_dir_contents() -> Result<String, Box<Error>> { // Open path let dir = Path::new("../FileSystem"); // Check if it is a directory if !dir.is_dir() { return Err(Box::from("Is not a directory!")); } for entry in fs::read_dir(dir)? { let path = entry?.path(); let file_name = path.file_name().unwrap(); println!("{}", file_name.to_string_lossy()); } Ok("Done".into()) } fn main() { match print_dir_contents() { Ok(s) => println!("{}", s), Err(e) => println!("Error: {}", e.to_string()), } } 

这里有很多的error handling,你可能不会指望 – 其他语言并不需要它! 但它们以其他语言存在 – Rust只是让你知道它。 这里是错误:

 entry? 

IO错误可能在迭代过程中发生。

 path.file_name().unwrap() 

并不是所有的path都有文件名。 我们可以unwrap这个,因为read_dir不会给我们一个没有文件名的path。

 file_name.to_string_lossy() 

你也可以to_str并抛出一个错误,但是这样做更好。 存在此错误是因为并非所有文件名都是有效的Unicode。

try!? 将错误引入返回值,将它们转换为Box::Error 。 返回所有可能出错的事物的合并错误实际上是更合理的。 幸运的是, io::Error只是正确的types:

 use std::io; ... fn print_dir_contents() -> Result<String, io::Error> { ... if !dir.is_dir() { return Err(io::Error::new(io::ErrorKind::Other, "Is not a directory!")); } ... } 

坦率地说,这个检查已经在fs::read_dir ,所以你可以直接删除if !dis.is_dir

 use std::io; use std::fs; use std::path::Path; fn print_dir_contents() -> Result<String, io::Error> { // Open path let dir = Path::new("../FileSystem"); for entry in fs::read_dir(dir)? { let path = entry?.path(); let file_name = path.file_name().unwrap(); println!("{}", file_name.to_string_lossy()); } Ok("Done".into()) } fn main() { match print_dir_contents() { Ok(s) => println!("{}", s), Err(e) => println!("Error: {}", e.to_string()), } } 

ques_in_main RFC最近被合并了。 一旦完成 ,问题中的语法将确实编译得很好,并按照预期工作,只要将try!()调用replace为? 运营商。