Rust临时值为何有时可引用有时不可?核心场景疑问
Rust临时值生命周期的核心规则解析
一、两段i32代码的差异本质
可运行代码:
fn main() { let a = &get_i32(); println!("{}", a); } fn get_i32() -> i32 { return 100; }
报错代码:
fn main() { let a; a = &get_i32(); println!("{}", a); }
编译器错误输出:
error[E0716]: temporary value dropped while borrowed --> src/bin/rust_course.rs:8:10 | 8 | a = &get_i32(); | ^^^^^^^^^- temporary value is freed at the end of this statement | | | creates a temporary value which is freed while still in use 9 | println!("{}", a); | - borrow later used here | help: consider using a `let` binding to create a longer lived value | 8 ~ let binding = get_i32(); 9 ~ a = &binding; | For more information about this error, try `rustc --explain E0716`.
差异核心是Rust的临时值生命周期延长规则:当使用let 变量 = &临时值的直接绑定形式时,编译器会自动将临时值的生命周期延长至与该变量一致。第一段代码中,get_i32()返回的临时i32值,生命周期被延长到和a相同,直到main函数结束才销毁,因此a的引用始终有效。
而第二段代码是先声明a再赋值,此时&get_i32()产生的临时值仅存活到当前语句结束(即a = &get_i32();执行完成),之后临时值被销毁,a变为悬空引用,触发E0716错误。
二、s1与s2的写法差异
代码示例:
fn main() { let s1 = &String::from("hello world"); println!("{}", s1); let s2 = String::from("hello world").as_str(); println!("{}", s2); }
编译器错误输出:
error[E0716]: temporary value dropped while borrowed --> src/bin/rust_course.rs:6:14 | 6 | let s2 = String::from("hello world").as_str(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement | | | creates a temporary value which is freed while still in use 7 | println!("{}", s2); | -- borrow later used here | help: consider using a `let` binding to create a longer lived value | 6 ~ let binding = String::from("hello world"); 7 ~ let s2 = binding.as_str(); | For more information about this error, try `rustc --explain E0716`.
s1的写法是&String::from(...),符合直接绑定引用到变量的规则,临时String的生命周期被延长至与s1一致,直到main函数结束,因此s1的引用有效。s2的写法是链式调用:String::from(...).as_str(),这种场景不触发生命周期延长——延长规则仅适用于let 变量 = &临时值的直接绑定形式,链式调用产生的临时值会在当前语句结束后立即销毁,导致s2变为悬空引用,触发错误。
三、传函数与赋值给变量的差异
可运行代码:
fn main() { print(String::from("hello world").as_str()); } fn print(str: &str) { println!("{}", str); }
这里的规则是:当临时值被用作函数参数时,它的生命周期会被延长到整个函数调用的持续时间。也就是说,在print(...)函数执行期间,临时String会一直存在,as_str()返回的引用在函数内部完全有效;函数执行完毕后,临时值才被销毁,此时引用已不再被使用,因此不会触发错误。
而赋值给变量时,变量的生命周期会超过当前语句(比如后续还有println!使用该变量),但临时值在语句结束就销毁,导致引用悬空,这就是两者的本质区别。
内容的提问来源于stack exchange,提问作者artzok
相关产品推荐
相关产品推荐

