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.
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 */
}
}