Reputation: 503
I am new to Rust. I am trying to build a JSON object where the keys are file names and the value is the file contents.
So far, I have:
use std::fs;
use std::io;
use std::env;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
fn main() {
make_json();
}
fn make_json() -> io::Result<()> {
let mut modules = HashMap::new();
let mut dir = env::current_dir().unwrap();
let mut read_dir = fs::read_dir(dir);
for entry in try!(read_dir) {
let entry = try!(entry);
let file_name = entry.path().file_name().unwrap().to_string_lossy();
modules.insert(file_name, "");
}
Ok(())
}
When I go to compile it, I get
src/main.rs:19:25: 19:37 error: borrowed value does not live long enough
src/main.rs:19 let file_name = entry.path().file_name().unwrap().to_string_lossy();
^~~~~~~~~~~~
note: in expansion of for loop expansion
src/main.rs:17:5: 21:6 note: expansion site
src/main.rs:13:38: 23:2 note: reference must be valid for the block suffix following statement 0 at 13:37...
src/main.rs:13 let mut modules = HashMap::new();
src/main.rs:14 let mut dir = env::current_dir().unwrap();
src/main.rs:15 let mut read_dir = fs::read_dir(dir);
src/main.rs:16
src/main.rs:17 for entry in try!(read_dir) {
src/main.rs:18 let entry = try!(entry);
...
src/main.rs:19:9: 19:77 note: ...but borrowed value is only valid for the statement at 19:8
src/main.rs:19 let file_name = entry.path().file_name().unwrap().to_string_lossy();
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/main.rs:19:9: 19:77 help: consider using a `let` binding to increase its lifetime
src/main.rs:19 let file_name = entry.path().file_name().unwrap().to_string_lossy();
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
I understand what this error is telling me; entry is defined within the scope of the for
loop, and therefore if I store it to the HashMap
it will no longer be valid memory because the place in memory will have been freed already. I get that.
What I don't get, is how I access the the DirEntry
s within read_dir
without using some sort of closure, since I will need their information outside of whatever closure I retrieve them in.
Everything that I have come across hasn't been able to help me.
Upvotes: 0
Views: 4133
Reputation: 3
Problem while dealing with Rust file system forced me to create this rust library brown
While dealing with Rust fs and specially while working with loops, the main issue is that every thing return another thing and then we need to convert that thing. We need something to flatten the items for us
My suggestion :: Do not do any calculations etc in a loop, it should just have function calls to a well tested library and just checking its results.
Upvotes: 0
Reputation: 90912
DirEntry.path()
returns a PathBuf
, which is 'static
(i.e. it contains no non-static references and is a completely standalong object). It is where the problem lies.
PathBuf.file_name()
returns Option<&OsStr>
, a reference into that object, and OsStr.to_string_lossy()
returns Cow<str>
. Note with that last that it is not 'static
; with the elided lifetimes reinstated, it’s fn to_string_lossy<'a>(&'a self) -> Cow<'a, str>
. This is for efficiency, because if the path is legal UTF-8 then there’s no need to go creating an entirely new owned string (String
), it can keep it as a string slice (&str
). (Because that’s what Cow<'a, str>
is: its variants, with generics filled in, are Owned(String)
and Borrowed(&'a str)
.)
What you need in this location is to turn the Cow<str>
into a String
. This is accomplished with the into_owned
method of Cow<T>
.
That line of code thus becomes this:
let file_name = entry.path().file_name().unwrap().to_string_lossy().into_owned();
Upvotes: 7