Перейдите по std:: fs:: ReadDir и получите только имена файлов из путей

Я пытаюсь понять, как сделать "список понимания" с ржавчиной. У меня есть ReadDir iter, который я хочу отобразить и получить только имена файлов. Я думаю, что это будет выглядеть примерно так:

// get current dir paths
let paths = fs::read_dir(&Path::new(
    &env::current_dir().unwrap())).unwrap();

// should contain only filenames
let files_names = paths.map(|&x| {
    match (*x).extensions() {
        Some(y) => y,
        None => //What do I do here? break?
};

Я знаю, что мое выражение, вероятно, ужасно нарушено, но есть ли способ сделать это единственным выражением, которое я могу связать file_names с?

Ответ 1

Вероятно, вы захотите использовать метод Path file_name(), который дает имя файла, если он является обычным файлом, поэтому он возвращает Option.

Я предполагаю, что вы хотите игнорировать имена файлов, которые не являются обычными файлами, то есть для которых file_name() вернет None, и в этом случае вы, вероятно, захотите использовать Iterator filter_map метод, который в основном похож на фильтр и карту, собранные вместе, то есть вы можете сопоставить (в данном случае путь → имя файла) и фильтровать, возвращая отображаемый результат как Option, где None означает, что вы хотите отфильтровать это значение.

Досадно, что вам нужно проверить каждый элемент, возвращенный итератором ReadDir, так как это тип Result, поэтому вам нужно будет увидеть, есть ли он Ok. Если вы просто хотите игнорировать записи не Ok (т.е. Err) в каталоге (например, записи, для которых у вас нет разрешения), вы можете просто преобразовать их в Option с помощью Result ok() и интегрируйте это в filter_map.

Вам также придется попытаться создать String из возвращаемого file_name(), так как это может быть не обязательно UTF-8. Файлы с именами, отличными от UTF-8, можно просто проигнорировать (в этом примере) снова, используя комбинацию map и and_then.

Вот как это выглядело бы, если бы вы проигнорировали записи и пути к каталогу не Ok, которые не являются обычными файлами (и, таким образом, возвращают None на file_name()), а также файлы, имена файлов которых не являются UTF-8:

let paths = fs::read_dir(&Path::new(
  &env::current_dir().unwrap())).unwrap();

let names =
paths.filter_map(|entry| {
  entry.ok().and_then(|e|
    e.path().file_name()
    .and_then(|n| n.to_str().map(|s| String::from(s)))
  )
}).collect::<Vec<String>>();

playpen

Если вы не очень хорошо знакомы с функциональными функциями управления потоком Rust, например. map, and_then и т.д. на Result и Option, то вот что бы оно выглядело как расширенное, без игнорирования ошибок и без обработки ошибок. Я оставляю это до вас:

let paths = fs::read_dir(&Path::new(
  &env::current_dir().unwrap())).unwrap();

let names =
paths.map(|entry| {
  let entry = entry.unwrap();

  let entry_path = entry.path();

  let file_name = entry_path.file_name().unwrap();

  let file_name_as_str = file_name.to_str().unwrap();

  let file_name_as_string = String::from(file_name_as_str);

  file_name_as_string
}).collect::<Vec<String>>();

playpen