2

This code walks the /tmp folder to show files that end in .txt:

const FOLDER_NAME: &str = "/tmp";
const PATTERN: &str = ".txt";

use std::error::Error;
use walkdir::WalkDir; // 2.2.9

fn main() -> Result<(), Box<dyn Error>> {
    println!("Walking folder {}", FOLDER_NAME);

    for entry in WalkDir::new(FOLDER_NAME).into_iter().filter_map(|e| e.ok()) {
        let x = entry.file_name().to_str();
        match x {
            Some(x) if x.contains(PATTERN) => println!("This file matches: {:?}", entry),
            _ => (),
        }
    }
    Ok(())
}

Although this works, is it possible to leverage filter_map to do the suffix filtering that's currently happening in match?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
struggling_learner
  • 1,214
  • 15
  • 29
  • Is the current `.filter_map(|e| e.ok())` behaviour of ignoring errors intentional? – Ry- Jan 02 '20 at 03:01
  • yes, there are a few folders in /tmp I don't have permissions to. example, `Err(Error { depth: 1, inner: Io { path: Some("/tmp/ssh-91erCI9EbnQJ"), err: Os { code: 13, kind: PermissionDenied, message: "Permission denied" } } })` – struggling_learner Jan 02 '20 at 03:04

1 Answers1

1

You need to return the entry wrapped in a Some when the condition is true:

use std::error::Error;
use walkdir::WalkDir; // 2.2.9

const FOLDER_NAME: &str = "/tmp";
const PATTERN: &str = ".txt";

fn main() -> Result<(), Box<dyn Error>> {
    println!("Walking folder {}", FOLDER_NAME);

    let valid_entries = WalkDir::new(FOLDER_NAME)
        .into_iter()
        .flat_map(|e| e)
        .flat_map(|e| {
            let name = e.file_name().to_str()?;
            if name.contains(PATTERN) {
                Some(e)
            } else {
                None
            }
        });

    for entry in valid_entries {
        println!("This file matches: {:?}", entry);
    }

    Ok(())
}

You'll note that I've secretly switched to Iterator::flat_map. Iterator::filter_map would also work, but I find flat_map more ergonomic, especially for your "ignore the errors" case.

It's debatable whether this is useful compared to a regular Iterator::filter call:

let valid_entries = WalkDir::new(FOLDER_NAME)
    .into_iter()
    .flat_map(|e| e)
    .filter(|e| {
        e.file_name()
            .to_str()
            .map_or(false, |n| n.contains(PATTERN))
    });

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366