为什么对临时结构(`&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
的两次调用都会失败,因为 a
和 b
都在内部块的末尾超出了范围。但是,由于某种原因,发生了以下情况:
- 创建对
NC
值的引用并将该引用存储在 a
中允许它足够长的时间。
- 创建一个
NC
值并将其存储在 b
中,然后为函数参数引用 b
会导致错误。
#[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.
在下面的 Rust 代码中,我预计对 pass_through
的两次调用都会失败,因为 a
和 b
都在内部块的末尾超出了范围。但是,由于某种原因,发生了以下情况:
- 创建对
NC
值的引用并将该引用存储在a
中允许它足够长的时间。 - 创建一个
NC
值并将其存储在b
中,然后为函数参数引用b
会导致错误。
#[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.