eiko
eiko

Reputation: 5345

How do I access files in a directory in Rust?

I've written a pretty straight-forward script based on the Rust docs:

use std::fs::{self, DirEntry};
use std::path::Path;

fn main() {
    let path = Path::new(".");
    for entry in fs::read_dir(path)? {
        let entry = entry?;
        let path = entry.path();
        if path.is_dir() {
            println!("directory found!");
        }
    }

}

but I get the following compile errors about ?:

error[E0277]: the trait bound `(): std::ops::Carrier` is not satisfied
 --> test.rs:6:18
  |
6 |     for entry in fs::read_dir(path)? {
  |                  -------------------
  |                  |
  |                  the trait `std::ops::Carrier` is not implemented for `()`
  |                  in this macro invocation
  |
  = note: required by `std::ops::Carrier::from_error`

error[E0277]: the trait bound `(): std::ops::Carrier` is not satisfied
 --> test.rs:7:21
  |
7 |         let entry = entry?;
  |                     ------
  |                     |
  |                     the trait `std::ops::Carrier` is not implemented for `()`
  |                     in this macro invocation
  |
  = note: required by `std::ops::Carrier::from_error`

I only partially understand ? but I know the gist is that it allows you to act on a Result only if it's an Ok. The error here is that it's being used on a () rather than a Result, which is weird. I tried implementing the loop without ?:

use std::fs::{self, DirEntry};
use std::path::Path;

fn main() {
    let path = Path::new(".");
    for entry in fs::read_dir(path) {
        println!("{}", entry.path());
    }

}

But I get the error:

error: no method named `path` found for type `std::fs::ReadDir` in the current scope
 --> test.rs:7:30
  |
7 |         println!("{}", entry.path());
  |                              ^^^^

Which implies that instead of fs::read_dir returning ReadDir which is an iterator over DirEntry items, fs::read_dir is returning () which is somehow an iterator over ReadDir items?

I'm so confused.

It's probably worth mentioning that i'm running: rustc 1.16.0 (30cf806ef 2017-03-10)

Upvotes: 1

Views: 8435

Answers (2)

E_net4
E_net4

Reputation: 29983

The ? operator and the try! macro will only work when your function returns a Result (in which the raised errors can be properly converted, of course). The main function does not return a result.

You may wish to send all of your code to a separate function and handle the error in main(), with something like this:

use std::io;
use std::fs::{self, DirEntry};
use std::path::Path;

fn main() {
    run().unwrap_or_else(|e| {
      println!("Something went wrong: {}", e.to_string());
    });
}

fn run() -> io::Result<()> {
    let path = Path::new(".");
    for entry in fs::read_dir(path)? {
        let entry = entry?;
        let path = entry.path();
        if path.is_dir() {
            println!("directory found!");
        }
    }
    Ok(())
}

Upvotes: 5

Shepmaster
Shepmaster

Reputation: 430711

The first error is because you cannot use try! or ? in a function returning ().

The second error is because read_dir returns a Result:

pub fn read_dir<P: AsRef<Path>>(path: P) -> Result<ReadDir>

Result implements IntoIterator, so path is actually the iterator you think you had.

Handling the errors and calling Path::display gets you what you want:

use std::fs;
use std::path::Path;

fn main() {
    let path = Path::new(".");
    for entry in fs::read_dir(path).expect("Unable to list") {
        let entry = entry.expect("unable to get entry");
        println!("{}", entry.path().display());
    }
}

Upvotes: 9

Related Questions