我正在尝试使用Rust列出目录中的所有目录(不是递归地)。我主要关注示例代码from the read_dir
docs,但我试图让它更简单,因为我知道目录是提前的,我不需要递归。
我明白了:
for entry in read_dir(Path::new("known-directory")) {
let path = entry.path();
if path.is_dir() {
print!("{}", entry);
}
}
自从我收到
的投诉后,这项工作无效
no method named `path` found for type `std::fs::ReadDir` in the current scope
似乎for
实际上没有迭代ReadDir
的条目。
我也尝试过try!(read_dir(Path::new("DefinitelyTyped")))
类似于文档中的内容,但这会产生
expected (), found enum `std::result::Result`
使用let entry = try!(entry)
也不起作用。
最终我想将这些目录条目推送到一个数组,对它进行排序,并对它进行JSON字符串化,但当然首先我必须能够正确地遍历这些条目。我怎么能这样做?
版本:rustc 1.13.0
使用:cargo 0.13.0
答案 0 :(得分:6)
让我们一起阅读编译器错误消息!
error: no method named `path` found for type `std::fs::ReadDir` in the current scope --> src/main.rs:5:26 | 5 | let path = entry.path(); | ^^^^
这意味着entry
的类型是ReadDir
,但这是怎么发生的?我们应该迭代ReadDir
!
如果我们查看documentation for read_dir
,我们可以看到它返回Result
:
pub fn read_dir<P: AsRef<Path>>(path: P) -> Result<ReadDir>
这意味着读取目录的过程可能会失败,这完全可信 - 如果目录不存在该怎么办?但是,提供的代码不处理该错误。它会将Result
传递给for
循环。通过调用for
来IntoIterator
循环工作,Result
实现这一点,产生Ok
个案例或根本没有。 Option
有类似的实现。
因此,您在代码中添加了try!
...
for entry in try!(fs::read_dir("/etc"))
error[E0308]: mismatched types --> src/main.rs:4:18 | 4 | for entry in try!(fs::read_dir("/etc")) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `std::result::Result` | = note: expected type `()` = note: found type `std::result::Result<_, _>` = note: this error originates in a macro outside of the current crate
与discussed previously一样documentation for try!
:
由于提前退货,
try!
只能在返回Result
的函数中使用。
你必须以某种方式处理错误,无论出于何种原因,你当前的函数声明它不会失败 - 它不会返回Result
!相反,让我们通过在呼叫中添加expect
来恐慌地杀死整个程序:
for entry in fs::read_dir("/etc").expect("I told you this directory exists")
(有些人使用unwrap
,但我会始终提倡expect
,因为它有更高的机会为经历最终失败的穷人提供有用的信息)
error: no method named `path` found for type `std::result::Result<std::fs::DirEntry, std::io::Error>` in the current scope --> src/main.rs:5:26 | 5 | let path = entry.path(); | ^^^^
是的,甚至可能存在更多失败案例。具体而言,阅读每个条目可能由于某种原因而失败这就是ReadDir
迭代器说
type Item = Result<DirEntry>
同样,你的功能仍然表明它不能失败,所以我们不得不再次恐慌:
let entry = entry.expect("I couldn't read something inside the directory");
error[E0277]: the trait bound `std::fs::DirEntry: std::fmt::Display` is not satisfied --> src/main.rs:9:26 | 9 | print!("{}", entry); | ^^^^^ trait `std::fs::DirEntry: std::fmt::Display` not satisfied | = note: `std::fs::DirEntry` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string = note: required by `std::fmt::Display::fmt`
正如错误消息中所述,将{}
更改为{:?}
,因为DirEntry
无法为最终用户设置格式。程序员可以处理调试格式。
use std::fs;
fn main() {
for entry in fs::read_dir("/etc").expect("I told you this directory exists") {
let entry = entry.expect("I couldn't read something inside the directory");
let path = entry.path();
if path.is_dir() {
print!("{:?}", entry);
}
}
}
我强烈建议您重新阅读error handling chapter The Rust Programming Language。我还主张基本记住为Result
和Option
实现的方法和特征,看看它们对Rust体验的核心程度。
这是一个返回错误的版本,并使用热门新闻尝试操作符(?
):
use std::fs;
use std::error::Error;
fn inner_main() -> Result<(), Box<Error>> {
for entry in fs::read_dir("/etc")? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
print!("{:?}", entry);
}
}
Ok(())
}
fn main() {
inner_main().expect("Unable to process");
}