Cannot use references of return values for the delay initialization of variables

In Rust, we can delay the initialization of variables like this:

let v;
// some other statements
v = &0;

However, when using the references of return values for the delay initialization of variables like this:

let v;
v = &String::from("hello");

The compiler reported an error. So did I violate some principles of the delay initialization of variables? Here is the error information.

error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:10:10
   |
10 |     v = &String::from("hello");
   |          ^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
   |          |
   |          creates a temporary value which is freed while still in use
11 |     println!("{}", v);
   |                    - borrow later used here
   |
help: consider using a `let` binding to create a longer lived value
   |
10 ~     let binding = String::from("hello");
11 ~     v = &binding;
   |

For more information about this error, try `rustc --explain E0716`.

No, this has nothing to do with initialization.

The error is exactly what the compiler says. A temporary is just that – a temporary, ie., it goes out of scope immediately (the precise rules are more complicated, but this is all what matters here). Thus, returning a reference to it would create a dangling reference.

Your example with the literal &0 shouldn't work, either, but it still does due to certain constant expressions undergoing so-called "static promotion" (google it).

BTW, when you need values, use values. Don't try to "return by reference". You are probably misunderstanding what references are for — you can't use them for keeping values alive.

1 Like

Thanks for your answer, I know this code snippet may not follow the design of Rust.

However, if I change this snippet into this:

let v = &String::from("hello");

It works well. So I guess this question may be related to the delay initialization, for I expect the reference is bound to the variable when executing v = &String::from("hello") and the variable will hold the temporary value. But actually, there is no binding and the value is dropped.

With let var = &expr, the temporaries in expr have their lifetime extended to match that of var. For var = &expr, this temporary lifetime extension does not happen. This has nothing to do with delayed intialization of variables. The following has the exact same issue:

let mut v = &String::from("hello");
v = &String::from("world");
println!("{v}");

And here too only the v = ... is reported as error. The let mut v = ... is accepted.

According to your words, there should be some difference between normal initialization and delayed initialization? Since in this situation, delayed initialization works like just normal assignment.

There's a special case where the compiler does some magic to help you, but that magic doesn't work in other cases.

let x = &expr() translates to:

 let hidden = expr();
 let x = &hidden;

but the compiler will not create a hidden let in more complex cases.

As a rule x = &expr() is not going work, because result of expr is not stored anywhere, and you cannot borrow a value that doesn't exist anywhere.

1 Like

You can read more about the special case for let here, or there's a more digestible article on the topic here.

1 Like

Thanks for answers above. So I can understand in this way that temporary lifetime extension is not considered during delayed initialization.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.