Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implicit ownership within Rust [duplicate]

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 614
Boiethios Avatar asked Nov 16 '22 04:11

Boiethios


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 141
Lukas Kalbertodt Avatar answered Jan 16 '23 18:01

Lukas Kalbertodt