阅读一级目录结构

时间:2016-11-11 15:44:15

标签: rust

我正在尝试使用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

运行

1 个答案:

答案 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循环。通过调用forIntoIterator循环工作,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。我还主张基本记住为ResultOption实现的方法和特征,看看它们对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");
}