I am simply trying to read the entries of a directory (Ubuntu Linux 22.10, ext4 filesystem):
let mut all_chosenfiles: Vec<&str> = Vec::new();
for next_path in path_components {
for next_dir_entry in fs::read_dir(next_path) {
for next_file in next_dir_entry {
let file_metadata = next_file.as_ref().unwrap().metadata().unwrap();
if file_metadata.is_file()
&& file_metadata.mode() & 0o500 == 0o500 {
let chosen_file = next_file.unwrap().path();
all_chosenfiles.push(chosen_file.to_owned().to_str().unwrap());
}
}
}
}
Not very idiomatic, I agree, but it serves the purpose at hand.
The compiler is not happy though:
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:31:46
|
31 | all_chosenfiles.push(chosen_file.to_owned().to_str().unwrap());
| ---------------------^^^^^^^^^^^^^^^^^^^^^^-------------------- temporary value is freed at the end of this statement
| | |
| | creates a temporary which is freed while still in use
| borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
I understand what is she complaining about. I have tried to pacify her, by using let
as has been prescribed [here]( [1]: E0716 - Error codes index):
for next_path in path_components {
for next_dir_entry in fs::read_dir(next_path) {
for next_file in next_dir_entry {
let file_metadata = next_file.as_ref().unwrap().metadata().unwrap();
if file_metadata.is_file()
&& file_metadata.mode() & 0o500 == 0o500 {
let chosen_path = next_file.unwrap().path();
let chosen_file = &chosen_path.to_owned().to_str().unwrap();
all_chosenfiles.push(chosen_file);
}
}
}
}
That `to_owned()' should have worked, IMO, but she is stubborn:
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:31:44
|
31 | let chosen_file = &chosen_path.to_owned().to_str().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
32 | all_chosenfiles.push(chosen_file);
| ----------- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
I am scratching my head. I am missing some idiom, I am sure.
Is a derefencing using '*' operator (viz., *chosent_file
) the only way out?
I have gotten around, for the time being, by:
let mut all_chosenfiles: Vec<String> = Vec::new(); // of String, and not of &str
for next_path in path_components {
for next_dir_entry in fs::read_dir(next_path) {
for next_file in next_dir_entry {
let file_metadata = next_file.as_ref().unwrap().metadata().unwrap();
if file_metadata.is_file()
&& file_metadata.mode() & 0o500 == 0o500 {
// Using as_ref() before unwrapping
let chosen_path: PathBuf = next_file.as_ref().unwrap().path();
// Doc says that, to_str()
// "Yields a &str slice if the Path is valid unicode"
let chosen_file: Option<&str> = chosen_path.to_str();
// Explicitly owning a String, made out of &str, below!
all_chosenfiles.push(chosen_file.unwrap().to_owned());
}
}
}
}
Honestly, I am not really sure why it is working. By calling next_file.as_ref()
, I ensure that a reference to that memory is held. But, how does that solve the problem of temporary which is freed etc.
issue? Moreover, cloning the pathstrings by using to_str()
seems to be wasteful to me.
There must be an idiom or a compact set of rules to follow, whenever one wants to write expressions like these.
Could you please point out, the gaps in my understanding?