1

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)

1
  • You may find this not having to do with accessing files in a directory at all: in the docs, that code was not inside main(). Commented Apr 13, 2017 at 14:54

2 Answers 2

9

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()); } } 
Sign up to request clarification or add additional context in comments.

7 Comments

thank you! this answers the question that lead me to say i only partially understood ? (that question being "what does ? do when the value isn't Ok?). is there a resource i missed? ? and try! wasn't mentioned in the rust book, but the docs seem to assume common knowledge of it.
@eiko rustbyexample.com/std/result/try.html. The ? operator is just sugar around try! so it should throw a compilation error about that type not implementing the carrier trait if it is not Result<U,V>.
@eiko the main resource I'd suggest is the error handling chapter of the book. try! is the previous idiomatic way for propagating errors, but ? has replaced it in newer versions of Rust. try! still exists for backwards-compatibility reasons.
@asteriskTheServer ? is not sugar around try!. If it was; you'd get the same error from using either, which is not currently the case. If anything, the try! macro should delegate to ?.
oops, i guess try! was in the book after all. i may have been skimming by the time i got to chapter 5.7 ^-^' thank you all for your help!
|
5

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(()) } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.