Фильтрация файлов или каталогов, обнаруженных с помощью fs :: read_dir () - PullRequest
0 голосов
/ 23 сентября 2019

У меня есть эта функция:

fn folders(dir: &Path) -> Result<Vec<PathBuf>, io::Error> {
    fs::read_dir(dir)?
        .into_iter()
        .map(|x| x.map(|entry| entry.path()))
        .collect()
}

На самом деле она заимствована из здесь .Функция в порядке;к сожалению, я не совсем понимаю, как это работает.

Ok(["/home/ey/dir-src/9", "/home/ey/dir-src/11", "/home/ey/dir-src/03 A Letter of Explanation.mp3", "/home/ey/dir-src/02 Egyptian Avenue.mp3", "/home/ey/dir-src/alfa", "/home/ey/dir-src/10"])

Результаты теста показывают как каталоги, так и файлы, как и должно быть.Я не могу понять, где поставить фильтрацию для файлов / каталогов.Я не понимаю, почему отображение внутри отображения: это не просто список путей?Что на самом деле происходит внутри этого выражения?

UPD:

fn folders(dir: &Path) -> Result<Vec<PathBuf>, io::Error> {
    fs::read_dir(dir)?
        .into_iter()
        .map(|x| x.map(|entry| entry.path()))
        .filter(|x| {x.as_ref().map(|entry| entry); true})
        .collect()
}

Вставлен тривиальный фильтр (всегда true).По крайней мере, он компилируется, но я все еще не понимаю, как я должен использовать entry для проверки файлов / каталогов.Извините:)

1 Ответ

1 голос
/ 23 сентября 2019

Давайте шаг за шагом пройдемся по цепочке.

fs::read_dir(dir)?

создает дескриптор чтения в каталог, немедленно распространяет случай Err, если это происходит, а если нет, unwrap sуспех (это оператор ?)

.into_iter()

превращает этот дескриптор чтения в итератор Result<DirEntry>

.map(|x|
  x.map(|entry| entry.path())
)

Это вызывает метод path() для каждого элементаитератор, если результат является действительным DirEntry.Поскольку элемент итератора Result<DirEntry>, а не просто DirEntry, второй map() позволяет вам разобраться с этим чисто.У вас остались пути, которые вы видите на выходе

.collect()

превращает этот итератор обратно в структуру, определяемую подсказками типов (здесь - вектор)

Может быть реализована фильтрующая частьдо или после вызова map(), чтобы превратить запись в PathBuf.Если вам нужно фильтровать по самому элементу, а не по PathBuf, фильтруйте перед ним.Если вы можете фильтровать на основе PathBuf, фильтруйте после него.

Использование функции комбинатора filter() не вызывает затруднений - вы закрываете ее, она будет применяться к каждому элементу.Если возврат закрытия равен true, элемент сохраняется.Если значение равно false, элемент удаляется.

Вот пример для возврата только каталогов:

fn folders(dir: &Path) -> Result<Vec<PathBuf>, io::Error> {
    Ok(fs::read_dir(dir)?
        .into_iter()
        .filter(|r| r.is_ok()) // Get rid of Err variants for Result<DirEntry>
        .map(|r| r.unwrap().path()) // This is safe, since we only have the Ok variants
        .filter(|r| r.is_dir()) // Filter out non-folders
        .collect())
}
...