I'm facing a problem with a value being dropped while it is still borrowed inside an Option
, in a closure, but I'm having a hard time grasping exactly what's going on. To illustrate, here is a working example of what I'm actually trying to achieve:
fn foo() -> Option<String> {
let hd = match std::env::home_dir() {
Some(d) => d,
None => return None,
};
let fi = match hd.file_name() {
Some(f) => f,
None => return None,
};
let st = match fi.to_str() {
Some(s) => s,
None => return None,
};
Some(String::from(st))
}
The return value is the base name of the current user's home directory inside Option<String>
.
I thought I'd try refactoring this with combinators to get rid of the lines None => return None,
.
std::env::home_dir()
.and_then(|d| d.file_name())
.and_then(|f| f.to_str())
.map(String::from)
But rustc detects a reference that outlives its value.
error: `d` does not live long enough
--> src/main.rs:33:35
|
33 | .and_then(|d| d.file_name())
| - ^ `d` dropped here while still borrowed
| |
| borrow occurs here
34 | .and_then(|f| f.to_str())
35 | .map(String::from)
| - borrowed value needs to live until here
I think this is because the reference in Option<&OsStr>
is outliving the value of type PathBuf
. However I'm still having a hard time figuring out how to approach this without having the value go out of scope too soon.
To further illustrate what I'm trying to achieve, here is a similar example with a type that implements the Copy trait.
let x = 42u16.checked_add(1234)
.and_then(|i| i.checked_add(5678))
.and_then(|i| i.checked_sub(90))
.map(|i| i.to_string());
println!("{:?}", x); // Some("6864")
So I'm definitely overlooking a few things related to ownership in the prior example. Is this possible with Option<PathBuf>
?
You're right that you're consuming the PathBuf
returned from home_dir()
but still trying to use references.
I would keep it in a variable, and work from there:
fn foo() -> Option<String> {
let path = std::env::home_dir();
path.as_ref()
.and_then(|d| d.file_name())
.and_then(|f| f.to_str())
.map(String::from)
}
The call to path.as_ref()
makes an Option<&PathBuf>
as the starting point for the chain of and_then
, without consuming the original owned PathBuf
which is needed at least until String::from
.