Search code examples
rustpattern-matchingmatchborrow-checkerownership

Match statement using moved matched variable throwing compiler error


I am attempting to iterate through a Vec<String> of file paths and read the content of the files. However, the match statement throws a compiler error regarding the variable in the pattern. The following is the code:

    //paths: Vec<String>
    //get counts in paths
    for path in paths.iter() {
        let mut path_result: Result<std::fs::File, std::io::Error>;
        let file: std::fs::File;

        if path != "-" {
            path_result = std::fs::File::open(&path);
        }

        //match result with error
        match path_result {
            Ok(path_file) => { file = path_file },
            Err(e) => {
                match e.kind() {
                    std::io::ErrorKind::NotFound => { println!("{}: No such file or directory", &path) },
                    std::io::ErrorKind::PermissionDenied => { println!("{}: Permission denied", &path) },
                    _ => {
                        println!("{}: Unknown error", &path);
                        panic!("unknown error opening file");
                    }
                }
                continue;
            }
        };
        
        /*get content from file variable*/
    }

This is the compiler error I receive:

error[E0382]: use of moved value
  --> src/main.rs:60:16
   |
51 |         let mut path_result: Result<std::fs::File, std::io::Error>;
   |             --------------- move occurs because `path_result` has type `std::result::Result<File, std::io::Error>`, which does not implement the `Copy` trait
...
60 |             Ok(path_file) => { file = path_file },
   |                ^^^^^^^^^ value used here after move
...
75 |     }
   |     -
   |     |
   |     value moved here, in previous iteration of loop
   |     value moved here, in previous iteration of loop

error: aborting due to previous error; 16 warnings emitted

For more information about this error, try `rustc --explain E0382`.
error: could not compile `test`

To learn more, run the command again with --verbose.

The warnings are in regards to unused variables not included in this snippet.

I have attempted borrowing the path_file variable's contents, but receive the same error. My understanding of the situation is that, because neither path_file nor path_result are used later in the for block and path_result is rebinded at the start, there should be no issue even if the ownership goes out of scope past the match statement. However, that seems to not be the case.


Solution

  • You cannot use uninitialized values in Rust. This code does not work:

    // declare path_result here
    let mut path_result: Result<std::fs::File, std::io::Error>;
    
    // conditionally initialize it here
    if path != "-" {
        path_result = std::fs::File::open(&path);
    }
    
    // potentially use uninitialized value: error!
    match path_result {
    

    The code above is also why you're getting the value moved here, in previous iteration of the loop error, because you're not actually initializing path_result in every iteration of the loop. Once you refactor the code to unconditionally initialize path_result in every iteration then it compiles:

    fn example(paths: Vec<String>) {
        for path in paths.iter() {
            if path == "-" {
                println!("skipping un-openable path: -");
                continue;
            }
    
            let file = match std::fs::File::open(&path) {
                Ok(path_file) => path_file,
                Err(e) => {
                    match e.kind() {
                        std::io::ErrorKind::NotFound => {
                            println!("{}: No such file or directory", &path)
                        }
                        std::io::ErrorKind::PermissionDenied => {
                            println!("{}: Permission denied", &path)
                        }
                        _ => {
                            println!("{}: Unknown error", &path);
                            panic!("unknown error opening file");
                        }
                    }
                    continue;
                }
            };
    
            /* get content from file variable */
        }
    }
    

    playground