关于Rust中E0716报错及三种相似代码编译差异的疑问
Rust生命周期:三段相似代码编译结果不同的原因解析
第一段代码:编译报错的原因
#[derive(Debug)] struct Test { val: i32 } fn main() { let a:&Test; let b = 32; a = &Test { val: b }; println!("{:?}", a.val); }
编译错误error[E0716]: temporary value dropped while borrowed的核心原因是临时值生命周期无法匹配提前声明的引用变量:
- 提前声明的
a是一个生命周期覆盖整个main函数的引用变量; - 赋值语句中创建的
Test { val: b }是临时值,它的构造依赖于当前作用域的变量b,Rust编译器不会对这类临时值进行生命周期提升,它会在当前语句执行完毕后立即被销毁; - 这就导致
a持有了一个已经被销毁的临时值的引用,形成悬垂引用,触发编译错误。
第二段代码:编译通过的原因
#[derive(Debug)] struct Test { val: i32 } fn main() { let a:&Test; let b = 32; a = &Test { val: 5 }; println!("{:?}", a.val); }
仅将val改为常量5后编译通过,是因为触发了Rust的临时值生命周期提升规则:
- 当临时值由常量表达式构造(不依赖任何当前作用域的变量)时,编译器会自动将这个临时值的生命周期延长到包含该引用的作用域(也就是整个
main函数周期); - 此时
a的引用生命周期和临时值的生命周期完全匹配,不会出现悬垂引用,因此可以正常编译。
第三段代码:编译通过的原因
#[derive(Debug)] struct Test { val: i32 } fn main() { let a:&Test; let b = 32; let a = &Test { val: b }; println!("{:?}", a.val); }
使用变量遮蔽重新声明a后编译通过,原因在于变量遮蔽创建了新的引用变量,编译器可以重新推断生命周期:
- 重新声明的
let a是一个全新的变量,编译器会为它和右侧的临时值绑定匹配的生命周期; - 临时值
Test { val: b }的生命周期会被延长到新a的生命周期结束(也就是main函数结束,因为后续要打印a.val); - 新
a的引用始终指向存活的临时值,不存在悬垂引用问题,因此编译通过。
内容的提问来源于stack exchange,提问作者Abraham Tugalov
相关产品推荐
相关产品推荐

