Bilal Syed Hussain
Bilal Syed Hussain

Reputation: 9224

How to filter file paths then use the resulting paths

I trying to get a list of mp3 from a directory.

let dir_paths = fs::read_dir(&Path::new("some_directory")).unwrap();

let paths = dir_paths.filter(|x| match x.unwrap().path().extension() {
    None => true,
    Some(ext) => ext == "mp3"
});

The Error Message

src/main.rs:27:48: 27:49 error: cannot move out of borrowed content
src/main.rs:27     let paths = dir_paths.filter(|ref x| match x.unwrap().path().extension() {
                                                              ^

I tried replacing |x| with |ref x| but got the same error message. What is correct way of doing this

Upvotes: 2

Views: 242

Answers (1)

Shepmaster
Shepmaster

Reputation: 432089

Let's take a look at the documentation for Result::unwrap:

fn unwrap(self) -> T

Unwraps a result, yielding the content of an Ok.

Note how it takes self? That means that the option will be consumed. However, your iterator is passing the closure a &Result<T, _>. You can't take ownership of the Option because it is borrowed.

The shortest fix is to get an Result<&T, _> instead, using as_ref:

use std::fs;

fn main() {
    let dir_paths = fs::read_dir("/").unwrap();

    let paths = dir_paths.filter(|x| match x.as_ref().unwrap().path().extension() {
        None => true,
        Some(ext) => ext == "mp3"
    });
}

Although I might choose to write it as

use std::fs;
use std::ffi::OsStr;

fn main() {
    let dir_paths = fs::read_dir("/").unwrap();

    dir_paths
        .filter_map(|x| x.ok())
        .filter(|x| x.path().extension().and_then(OsStr::to_str) == Some("mp3"));
}

There's some less unwraps - we just ignore any failed DirEntrys. That's up to your error handling strategy though.

Upvotes: 4

Related Questions