为什么要编译此代码?

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

fn main() {
    let _it = get_iter();
}


[1, 2, 3]是局部变量,iter()借用了它。该代码不应编译,因为返回的值包含对局部变量的引用。

#1 楼

在您的示例中,[1, 2, 3]不被视为局部变量,而是静态变量!

让我们看一下以下代码:

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


这可行!

前段时间,RFC 1414:合并了Rvalue静态升级:“将constexpr rvalues升级为静态内存中的值,而不是堆栈插槽中的值”。这意味着基本上您编写的所有文字都可以永远存在。因此,像let _: &'static i32 = &42;之类的东西也可以使用!

如果我们避免使用文字数组,我们可以看到预期的错误:

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


这里出现“ v寿命不足”错误。

这不限于整数或数组;它广泛适用于仅由文字组成的任何文字:

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')
}



除了文字,它也适用于标准库中的极少数函数,但是这些可能是一个错误。决定是否可以将任意const函数的结果自动提升到static仍然是一个悬而未决的话题。

评论


似乎const变量已过时:p

– Boiethios
18年5月15日在8:09

@Boiethios这是一个有趣的想法。您是否找到可以链接的讨论?

–宇宙
18年5月15日在8:14

@Boiethios他们不是过时的。这仅适用于文字。有时,您需要一个必须计算的const。

– Peter Hall
18年5月15日在9:53

@Boiethios将数据存储在静态内存中有一些弊端,尤其是当数据很大时,并且对于程序的整个生命周期而言并不是必需的。在某些时候,您肯定必须选择加入该行为。

– Peter Hall
18年5月15日在10:05

@Alexey是的,这就是语言模型所说的。但是,无论如何,优化器仍然可以稍后内联该值。

–卢卡斯(Lukas Kalbertodt)
4月20日7:51