生命周期标注 'a 是 Rust 里最容易被误解的语法:它不是「让某个值活更久」,而是「描述几个引用的有效期之间的关系」。这篇用一个 longest 函数,从四个角度验证这一点,最后用汇编确认它在运行时完全不存在。
源码:
1 | fn longest(x: &str, y: &str) -> &str { if x.len() > y.len() { x } else { y } }
2 | fn main() { println!("{}", longest("abc", "de")); }
编译:失败
error[E0106]: missing lifetime specifier
--> <实验目录>/src/u23a.rs:1:33
|
1 | fn longest(x: &str, y: &str) -> &str { if x.len() > y.len() { x } else { y } }
| ---- ---- ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y`
help: consider introducing a named lifetime parameter
|
1 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } }
| ++++ ++ ++ ++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0106`.
源码:
1 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } }
2 | fn main() { println!("{}", longest("abc", "de")); }
编译:成功
运行(退出码 0):
abc 源码:
1 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } }
2 | fn main() {
3 | let a = String::from("long string");
4 | let result;
5 | {
6 | let b = String::from("xyz");
7 | result = longest(a.as_str(), b.as_str());
8 | }
9 | println!("{}", result);
10 | }
编译:失败
error[E0597]: `b` does not live long enough
--> <实验目录>/src/u23c.rs:7:38
|
6 | let b = String::from("xyz");
| - binding `b` declared here
7 | result = longest(a.as_str(), b.as_str());
| ^ borrowed value does not live long enough
8 | }
| - `b` dropped here while still borrowed
9 | println!("{}", result);
| ------ borrow later used here
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0597`.
源码:
1 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } }
2 | fn main() {
3 | let a = String::from("long string");
4 | {
5 | let b = String::from("xyz");
6 | let result = longest(a.as_str(), b.as_str());
7 | println!("在内层使用 result:{}", result);
8 | }
9 | }
编译:成功
运行(退出码 0):
在内层使用 result:long string 源码:
1 | fn first<'a, 'b>(x: &'a str, y: &'b str) -> &'a str { let _ = x; y }
2 | fn main() { println!("{}", first("a", "b")); }
编译:失败
error: lifetime may not live long enough
--> <实验目录>/src/u23e.rs:1:66
|
1 | fn first<'a, 'b>(x: &'a str, y: &'b str) -> &'a str { let _ = x; y }
| -- -- lifetime `'b` defined here ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
| |
| lifetime `'a` defined here
|
= help: consider adding the following bound: `'b: 'a`
error: aborting due to 1 previous error
源码:
1 | fn first<'a, 'b>(x: &'a str, _y: &'b str) -> &'a str { x }
2 | fn main() {
3 | let a = String::from("long");
4 | let r;
5 | { let b = String::from("short"); r = first(&a, &b); } // 返回值只与 a 相关,b 先死也没关系
6 | println!("{r}");
7 | }
编译:成功
运行(退出码 0):
longelided 与 explicit 共同的汇编: add x0, x0, #4 ; ret 别名行: `_explicit = _elided`(LLVM 合并了两个相同的函数) size_of::<&u32>() 在有无生命周期标注时都是 8 字节;生命周期只在编译期存在
省略规则见生命周期省略规则;函数返回引用的具体情形见函数返回引用的生命周期。