0

While trying to print out my home directory I came across the following error:

fn main() {
    let home = home::home_dir().unwrap().to_str().unwrap();
    println!("home dir: {}", home);
}
error[E0716]: temporary value dropped while borrowed
 --> src/main.rs:3:16
  |
3 |     let home = home::home_dir().unwrap().to_str().unwrap();
  |                ^^^^^^^^^^^^^^^^^^^^^^^^^                  - temporary value is freed at the end of this statement
  |                |
  |                creates a temporary which is freed while still in use
4 |     println!("home dir: {}", home);
  |                              ---- borrow later used here
  |
  = note: consider using a `let` binding to create a longer lived value

But if I split the part underlined in the error message and put it in a separate variable it works:

fn main() {
    let home_buf = home::home_dir().unwrap();
    let home_str = home_buf.to_str().unwrap();
    println!("home dir: {}", home_str);
}

My question is what's the difference between the two examples?
(I'm using the home crate in my code)

jmezo
  • 13
  • 2

2 Answers2

3

home::home_dir().unwrap() provides a std::path::PathBuf. Invoking .to_str().unwrap() provides a reference to something that is stored inside the preceding PathBuf. Thus, for the reference to be valid, the PathBuf must exist (and Rust enforces that).

In your first expression, the PathBuf is a temporary that will be dropped straight away; the reference home would be dangling! (it's an error).

In your second example, the home_buf binding keeps the PathBuf alive, then the reference home_str can be used as long as home_buf exists.

prog-fh
  • 13,492
  • 1
  • 15
  • 30
2

Another way to look at it is that your original code is roughly equivalent to:

fn main() {
    let home;
    {
        let tmp1: Option<PathBuf> = home::home_dir();
        let tmp2: PathBuf = tmp1.unwrap();
        let tmp3: Option<&str> = tmp2.to_str();
        home = tmp3.unwrap();
    }
    println!("home dir: {}", home);
}

In other words, all the temporary values created by an expression last as long as the expression, and no longer than that. Storing a reference that borrows from tmp2 into home is not allowed because, the reference would then outlive the value it borrows from.

By introducing a variable to hold the PathBuf, you made it last longer than the expression, and the reference becomes valid.

user4815162342
  • 141,790
  • 18
  • 296
  • 355