为什么对临时结构(`&Foo { … }`)的引用可以存活足够长的时间,而对变量的引用(`let foo = Foo { … }; &foo`)却不能?

Why does a reference to a temporary struct (`&Foo { … }`) live long enough, but a reference to a variable (`let foo = Foo { … }; &foo`) does not?

在下面的 Rust 代码中,我预计对 pass_through 的两次调用都会失败,因为 ab 都在内部块的末尾超出了范围。但是,由于某种原因,发生了以下情况:

#[derive(Debug)]
struct NC(i32);

fn pass_through(x: &NC) -> &NC {
    x
}

fn main() {
    let a2: &NC;
    let b2: &NC;
    {
        let a = &NC(1);
        a2 = pass_through(a);  // Works fine

        let b = NC(2);
        b2 = pass_through(&b); // Error, borrowed value does not live long enough
    }
    println!("a2 - {:?}", a2);
    println!("b2 - {:?}", b2);
}

为什么借用检查员对这两种情况的处理方式不同?

这可能是由于编译器确定引用生命周期的方式所致。

在变量 a 的情况下,编译器分析整个块,发现变量 a2 的最长生命周期,将被分配一个引用,延长其生命周期,因为变量不拥有数据。

但是,在b的情况下,一切都不同了,变量拥有数据,这意味着当你退出块时,数据将被删除并且link 将有效。

这适用于 let a 情况,因为 &NC(1) 引用由编译器自动创建的 read-only 静态。 a 的推断类型包括生命周期。

// These two lines are equivalent:
let a = &NC(1);
let a: &'static NC = &NC(1);

'static 生命周期对整个程序有效,因此永远不会 'static 引用分配给某物时出现生命周期错误。行 a2 = pass_through(a); 起作用是因为 a2 的生命周期与 a 的生命周期无关。所有这一切都是将存储在 a 中的引用复制到 a2,因此 a2 根本不依赖于 a 的生命周期。 它们都是 &NC 引用相同值的变量。我想这就是你困惑的地方。

b 案例失败,因为 b2 引用超过了 b 的生命周期。

需要注意的是fall_through的签名中有一个隐藏的生命周期参数。就好像你写了这个:

fn pass_through<'a>(x: &'a NC) -> &'a NC {

这只是意味着返回引用的生命周期与输入引用的生命周期相同。在 pass_through(a) 调用中,生命周期参数 'a 变为 'static。在 pass_through(b) 调用中,生命周期参数 'a 匹配 b 的生命周期。换句话说,这个函数是一个简单的恒等函数——它 returns 它的参数,无论是它的值还是它的 type/lifetime.