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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With