为什么试试!()和? 在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为?
运营商。