2016-11-11 8 views
-1

Я пытаюсь перечислить все каталоги (не рекурсивно) в каталоге с использованием Rust. Я в основном следую примеру кода from the read_dir docs, но я пытаюсь сделать его проще, так как я знаю, что каталог раньше времени, и мне не нужно рекурсивно.Прочитать один уровень структуры каталогов

Я его вниз:

for entry in read_dir(Path::new("known-directory")) { 
    let path = entry.path(); 

    if path.is_dir() { 
     print!("{}", entry); 
    } 
} 

Это не работает, так как я получаю жалобы

no method named `path` found for type `std::fs::ReadDir` in the current scope

Похоже, for на самом деле не итерацию над записи ReadDir.

Я также попытался try!(read_dir(Path::new("DefinitelyTyped"))), похожий на то, что в документации, но это дает

expected(), found enum `std::result::Result`

Использование let entry = try!(entry) не работает.

В конечном итоге я хотел бы переместить эти записи в каталог, отсортировать его и JSON-stringify, но, конечно, сначала я должен иметь возможность правильно выполнять итерацию записей. Как я могу это сделать?

Версия: rustc 1.13.0
Бег с: cargo 0.13.0

+2

Примечание: с помощью 'попробовать' макрос, или так как вы на 1.13 Оператор '?' требует функции, в которой он вызывается, чтобы вернуть «Результат»; это то, что 'ожидаемый(), найденный enum ...' говорит вам. –

+0

@Shepmaster: Если я получаю это право, 'read_dir' возвращает результат, который реализует' IntoIterator', приводящий к фактическому экземпляру 'ReadDir', который выполняет ИИ вместо записей каталога. –

+0

@ MatthieuM. yep – Shepmaster

ответ

6

Давайте читать сообщения об ошибках компилятора вместе!

error: no method named `path` found for type `std::fs::ReadDir` in the current scope 
--> src/main.rs:5:26 
    | 
5 |   let path = entry.path(); 
    |       ^^^^ 

Это означает, что тип entry является ReadDir, но как же это случилось? Предполагается, что мы будем перебирать ReadDir!

Если мы посмотрим на documentation for read_dir, мы можем видеть, что она возвращает Result:

pub fn read_dir<P: AsRef<Path>>(path: P) -> Result<ReadDir> 

Это означает, что процесс чтения каталога может потерпеть неудачу, что вполне правдоподобно - что, если каталог Безразлично» t существует? Однако представленный код не обрабатывает эту ошибку. Вместо этого он передает Result в цикл for. for работает с помощью IntoIterator и Result, что дает Ok случай или вообще ничего. Option имеет аналогичную реализацию.

Итак, вы добавили try! в код ...

for entry in try!(fs::read_dir("/etc")) 
error[E0308]: mismatched types 
--> src/main.rs:4:18 
    | 
4 |  for entry in try!(fs::read_dir("/etc")) { 
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected(), found enum `std::result::Result` 
    | 
    = note: expected type `()` 
    = note: found type `std::result::Result<_, _>` 
    = note: this error originates in a macro outside of the current crate 

Как уже discussed previously и упоминается в documentation for try!:

Из-за раннего возвращения, try! может использоваться только в функциях, которые возвращают Result.

Вы должны обрабатывать ошибки как-то, и по какой-либо причине, текущая функция утверждает, что она не может не - это не возвращает Result! Вместо этого давайте просто убить всю программу паниковать, добавляя expect к вызову:

for entry in fs::read_dir("/etc").expect("I told you this directory exists") 

(Некоторые люди используют unwrap, но я буду всегда выступает за expect как он имеет более высокую вероятность предоставления полезной информации для бедные души, которые испытывают возможный отказ)

error: no method named `path` found for type `std::result::Result<std::fs::DirEntry, std::io::Error>` in the current scope 
--> src/main.rs:5:26 
    | 
5 |   let path = entry.path(); 
    |       ^^^^ 

Да, есть еще более Возможны случаи отказа. В частности, по какой-то причине чтение каждой записи может завершиться неудачей. Вот почему ReadDir итератора говорит

type Item = Result<DirEntry> 

Опять же, ваша функция по-прежнему утверждает, что не может потерпеть неудачу, поэтому мы должны паниковать снова:

let entry = entry.expect("I couldn't read something inside the directory"); 
error[E0277]: the trait bound `std::fs::DirEntry: std::fmt::Display` is not satisfied 
--> src/main.rs:9:26 
    | 
9 |    print!("{}", entry); 
    |       ^^^^^ trait `std::fs::DirEntry: std::fmt::Display` not satisfied 
    | 
    = note: `std::fs::DirEntry` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string 
    = note: required by `std::fmt::Display::fmt` 

Как указано также в ошибке сообщение, изменить {} до {:?}, потому что DirEntry не имеет надлежащего способа форматирования для конечных пользователей. Программисты могут работать с форматом отладки.


use std::fs; 

fn main() { 
    for entry in fs::read_dir("/etc").expect("I told you this directory exists") { 
     let entry = entry.expect("I couldn't read something inside the directory"); 
     let path = entry.path(); 

     if path.is_dir() { 
      print!("{:?}", entry); 
     } 
    } 
} 

Я настоятельно рекомендую перечитывая error handling chapter из The Rust Programming Language. Я также выступаю за то, чтобы в основном заучивать методы и черты, реализованные для Result и Option, видя, насколько ядром для них является опыт Rust.

Вот версия, которая возвращает ошибку и использует оператор горячей вне-пресс TRY (?):

use std::fs; 
use std::error::Error; 

fn inner_main() -> Result<(), Box<Error>> { 
    for entry in fs::read_dir("/etc")? { 
     let entry = entry?; 
     let path = entry.path(); 

     if path.is_dir() { 
      print!("{:?}", entry); 
     } 
    } 

    Ok(()) 
} 

fn main() { 
    inner_main().expect("Unable to process"); 
} 
+0

Спасибо, это действительно прояснилось довольно много. Я не знал о 'expect' и' unwrap'. –

Смежные вопросы