Having trouble getting this function working. I believe I understand what the errors are trying to tell me, but I don't understand how I'm committing the errors / how to resolve them.
The function is a recursive function that looks through a directory and its subdirectories and accumulates a vector of the path and an Axum MethodRouter (which I don't believe has any bearing on the actual issue I'm facing).
The compiler error states "cannot return value referencing local variable path
."
If I replace path.to_str()
with path.clone().to_str()
, the error becomes, "cannot return value referencing temporary value."
fn assign_handlers(dir: Option<&str>) -> Vec<(&str, MethodRouter)> {
//Check root dir validity
let dir = match dir {
Some(s) => s,
None => return vec![],
};
//Look for routes in dir
let dir_path = fs::read_dir(dir).expect(&format!("Unable to access directory '{}'", &dir));
let mut routes = Vec::new();
for entry in dir_path {
match entry {
Ok(entry) => {
let path = entry.path();
if path.is_dir() {
//Recurse into subdirectories
let subroutes = assign_handlers(path.to_str());
for route in subroutes {
routes.push(route)
}
} else if path.is_file() {
// Cut for brevity (and because I don't know what goes here yet)
}
},
Err(_) => {},
}
}
routes
}
Rust is correct. Let's decode &str
: the &
means that it is a reference and str
means that it is the contents of a string. In garbage-collected languages, references keep the object alive, which is convenient, but Rust has made a different choice, that is usually faster and more memory-efficient, and that can be used to find lots of bugs that the compiler would let pass in other languages: a reference does not keep an object alive.
This is what the compiler tells you: a temporary value is, by definition, one that ceases existing once you leave the block. Since the return type that you specify in the function contains &str
, the compiler trusts you and assumes that subroutes
contains temporary values and that you're trying to return them. And since you can't return a temporary value, you get an error.
So, what you should do is instead return something that is guaranteed to remain alive. This could be a String
, for instance. Except, in this case, you already have something that is alive: a PathBuf
- that's equivalent to a String
, except it uses the encoding of your file system, as required by your operating system (many languages confuse a PathBuf
and a String
– this makes most applications written in these languages unusable in Japan, Korea or China, for instance).
With these changes, you get:
fn assign_handlers(dir: Option<&Path>) -> Vec<(PathBuf, MethodRouter)> {
//Check root dir validity
let dir = match dir {
Some(s) => s,
None => return vec![],
};
//Look for routes in dir
let dir_path = fs::read_dir(dir).expect(&format!("Unable to access directory '{:?}'", &dir));
let mut routes = Vec::new();
for entry in dir_path {
match entry {
Ok(entry) => {
let path = entry.path();
if path.is_dir() {
//Recurse into subdirectories
let subroutes = assign_handlers(Some(&path));
for route in subroutes {
routes.push(route)
}
} else if path.is_file() {
}
},
Err(_) => {},
}
}
routes
}
Also, I'm not sure why you pass an Option<&PathBuf>
. I would suggest passing just a &PathBuf
. This would simplify the code a bit.