Using try! to Unwrap Results from Directory Operations in Rust

I’ve been looking for an excuse to dive deeper into Rust now that it has reached a stable version (v1.0).  With some recent consolidation of some old hard drives, I have need of a fast duplicate file detector.  I thought that was the perfect excuse to play with Rust and see how it performed.

The first step in finding a duplicate file is to read the file system, so I set out to convince Rust to read a directory and print the results.  My early investigation was promising – the std::fs module was (mostly) stable and had a method to read a directory – read_dir().

Things were looking good –  a quick dive through the documentation lead me to the DirEntry struct, which had a code snippet that read the current directory and printed it.  Problem solved:

use std::fs;
for entry in try!(fs::read_dir(".")) {
    let dir = try!(entry);
    println!("{:?}", dir.path());
}

A little manipulation to turn that snippet into an executable program and I was ready to go.  Unfortunately, the snippet fails to compile with two identical errors:

:5:8: 6:42 error: mismatched types:
 expected `()`,
    found `core::result::Result<_, _>`
(expected (),
    found enum `core::result::Result`) [E0308]
:5 return $ crate:: result:: Result:: Err (
:6 $ crate:: convert:: From:: from ( err ) ) } } )
:1:1: 6:48 note: in expansion of try!
:3:18: 3:41 note: expansion site
:5:8: 6:42 error: mismatched types:
 expected `()`,
    found `core::result::Result<_, _>`
(expected (),
    found enum `core::result::Result`) [E0308]
:5 return $ crate:: result:: Result:: Err (
:6 $ crate:: convert:: From:: from ( err ) ) } } )
:1:1: 6:48 note: in expansion of try!
:4:19: 4:30 note: expansion site
error: aborting due to 2 previous errors

While most of that message is rather obtuse, it does offer a clue in the note: section – apparently the 2 try! macros were to blame. 

Once I realized that, I could focus on why I was getting the error.  My Google-fu turned up no suggestions, and the documentation samples all used try!, so I turned to the source. The read_dir source offered no clues – it returned the Result struct that try! was expecting.  My next step was to look up the source for try!, and the very first result was a bug report “try! not usable in main()”.

Oops.

Turns out this issue is “by design”.  Since main returns “()”, and try! can return an error, you get a type mismatch, and the (now much clearer) error E0308 referenced above.  Fortunately, now that I understood the problem, the solution was simple – just unwrap()the result and let the program panic if it failed.

use std::fs;
fn main() {
    for entry in fs::read_dir(".").unwrap() {
        let dir = entry.unwrap();
        println!("{:?}", dir.path());
    }
}