Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can I return a reference to a local literal but not a variable?

Why does this code compile?

fn get_iter() -> impl Iterator<Item = i32> {     [1, 2, 3].iter().map(|&i| i) }  fn main() {     let _it = get_iter(); } 

[1, 2, 3] is a local variable and iter() borrows it. This code should not compile because the returned value holds a reference to a local variable.

like image 601
Boiethios Avatar asked May 15 '18 07:05

Boiethios


People also ask

Can you return a reference to a local variable?

Local variables cannot be returned by reference.

Why should we not return a reference or an address of a local variable?

The return statement should not return a pointer that has the address of a local variable ( sum ) because, as soon as the function exits, all local variables are destroyed and your pointer will be pointing to someplace in the memory that you no longer own.

Can I return a local variable in C++?

C++ How to return a local variable from a function? But there is a way to access the local variables of a function using pointers, by creating another pointer variable that points to the variable to be returned and returning the pointer variable itself.

Can a reference be the return type for a function?

Functions can be declared to return a reference type. There are two reasons to make such a declaration: The information being returned is a large enough object that returning a reference is more efficient than returning a copy. The type of the function must be an l-value.


1 Answers

In your example, [1, 2, 3] is not treated as local variable, but as static one!

Let's take a look at this code:

fn foo() -> &'static [i32] {     &[1, 2, 3] } 

This works!

Some time ago, RFC 1414: Rvalue Static Promotion was merged: "Promote constexpr rvalues to values in static memory instead of stack slots". This means that basically all literals you write can live forever. Thus, things like let _: &'static i32 = &42; also work!

If we avoid using a literal array, we can see the expected error:

fn bar() -> impl Iterator<Item = i32> {     vec![1, 2, 3].iter().map(|&i| i) } 

Here we get the "v does not live long enough" error.

This isn't limited to integers or arrays; it applies broadly to any literal that is composed solely of literals:

fn promote_integer() -> &'static i32 {     &42 } 
fn promote_float() -> &'static f64 {     &42.42 } 
fn promote_str() -> &'static str {     "Hello World!" } 
struct Foo(char);  fn promote_struct() -> &'static Foo {     &Foo('x') } 

Beyond literals, this also works for a tiny number of functions in the standard library, but these were likely a mistake. Deciding on if the result of arbitrary const functions can be automatically promoted to static is still an open topic.

like image 135
Lukas Kalbertodt Avatar answered Oct 01 '22 06:10

Lukas Kalbertodt