Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

using std::fs::read_dir as an iterator in Rust

I’m new to Rust(about a month), and this is my first time asking a question in this platform.
please excusing me for making a few mistakes.
Right now, I’m trying to make a save system that copies the whole directory.
It looks like this:

[File hierarchy]

Documents

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

  • tosave
  • logs
  • write_log (the thing I’m making)

[main.rs]

use std::fs::{copy,create_dir,read_dir};
use std::path::{Path,PathBuf};

fn copy_dir(cp_path: &Path,wr_path: &Path){
    // if cp_path is a directory, repeat self to every components
    if cp_path.is_dir(){
        create_dir(&wr_path);
        for each_file in read_dir(cp_path) {
            //dynamic path to edit
            let mut pathbuf = PathBuf::new();
            pathbuf.push(&wr_path);
            match each_file {
                Ok(i) => {
                    let file_path = i.path().as_path();
                    match file_path.file_name(){
                        Some(name) =>{
                            let filename = Path::new(&name);
                            pathbuf.push(&filename);
                            //recurse
                            copy_dir(&file_path,&pathbuf.as_path());
                        }
                        None => {
                            //create an empty dir if name isn't valid
                            pathbuf.push(&Path::new("N/A"));
                            create_dir(pathbuf.as_path());
                        }
                    }
                }
                Err(e) => {
                    panic!();
                }
            }
        }
    }else{  copy(&cp_path,&wr_path); }
}

fn main() {
    let copy_path = Path::new("tosave");
    let write_path = Path::new("logs/foo");
    copy_dir(&copy_path,&write_path);
}

When I tried to compiled the code, an error occurred.

error[E0308]: mismatched types
  --> src/main.rs:12:17
   |
11 |             match each_file {
   |                   --------- this expression has type `ReadDir`
12 |                 Ok(i) => {
   |                 ^^^^^ expected `ReadDir`, found `Result<_, _>`
   |
   = note: expected struct `ReadDir`
                found enum `Result<_, _>

I was expecting each_file’s type to be ‘Option<Result>’.
but it appears the ‘for ~ in’ loop didn’t function properly,
and it somehow gave each_file a ReadDir.
please help me on this.

(documents I referenced)

https://doc.rust-lang.org/std/fs/fn.read_dir.html
https://doc.rust-lang.org/std/fs/struct.ReadDir.html

>Solution :

If we remove the loop body, the compiler can be of help:

fn copy_dir(cp_path: &Path, wr_path: &Path) {
    // if cp_path is a directory, repeat self to every components
    if cp_path.is_dir() {
        create_dir(&wr_path);
        for each_file in read_dir(cp_path) {
        }
    } else {
        copy(&cp_path, &wr_path);
    }
}
warning: for loop over a `Result`. This is more readably written as an `if let` statement
 --> src/main.rs:8:26
  |
8 |         for each_file in read_dir(cp_path) {
  |                          ^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(for_loops_over_fallibles)]` on by default
help: to check pattern in a loop use `while let`
  |
8 |         while let Ok(each_file) = read_dir(cp_path) {
  |         ~~~~~~~~~~~~~         ~~~
help: consider using `if let` to clear intent
  |
8 |         if let Ok(each_file) = read_dir(cp_path) {

Playground.

What happens is that read_dir() returns Result<ReadDir, std::io::Error>. You intended to iterate over the ReadDir (which is an iterator over Result<DirEntry, std::io::Error>, but you are actually iterating over the Result. This is not a direct error because Result implements IntoIterator – it yields the Ok value if Ok, or nothing if Err. This is useful for e.g. ignoring errors in an iterator by flatten()ing it.

You need to handle the Result, e.g. by unwrap()ing it.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading