【Rust自学】10.6. 生命周期 Pt.2:生命周期的语法与例子

发布时间:2026/7/23 18:52:10
【Rust自学】10.6. 生命周期 Pt.2:生命周期的语法与例子 10.6 生命周期 Pt.2生命周期的语法与例子10.6.1. 生命周期标注语法标注生命周期并不会改变引用存活多久。如果某个函数指定了泛型生命周期参数那么它可以接收带有任何生命周期的引用。生命周期标注主要用于描述多个引用的生命周期之间的关系但它们本身并不影响生命周期。生命周期参数名必须以开头通常是全小写且非常短。很多开发者使用a作为生命周期参数名。生命周期标注放在符号后面并在标注与引用类型之间用空格隔开。10.6.2. 生命周期标注例子i32一个普通引用a i32带有显式生命周期的引用被引用的类型是i32a mut i32带有显式生命周期的可变引用单个生命周期标注本身没有意义。生命周期标注的目的是向 Rust 描述多个泛型生命周期之间的关系。以 10.5 生命周期 Pt.1生命周期的定义与意义、借用检查器与泛型生命周期 的代码为例fn main() { let string1 String::from(abcd); let string2 xyz; let result longest(string1.as_str(), string2); println!(The longest string is {result}); } fn longesta(x: a str, y: a str) - a str { if x.len() y.len() { x } else { y } }longest中参数x、参数y以及返回值的生命周期都是a这意味着x、y和返回值必须拥有“相同”的生命周期。从上面的例子也可以看出在函数签名中使用生命周期标注时必须把泛型生命周期参数声明在里。这个签名告诉 Rust存在一个生命周期a并且x、y和返回值必须至少活得和a一样长。因为生命周期标注主要用于描述多个引用的生命周期之间的关系但它们本身并不影响生命周期所以这样写并不会改变实参的生命周期。它只是给借用检查器提供了一些可用于检测非法调用的约束。因此longest函数并不需要知道x和y到底活多久它只需要某个作用域可以用来代替a同时满足函数签名的约束即可。当函数引用外部代码或被外部代码引用时几乎不可能单靠 Rust 编译器确定参数和返回值的生命周期。这样的函数所使用的生命周期可能在每次调用时都会变化。这正是有时需要手动标注生命周期的原因。在示例代码中当我们把具体引用传入longest函数时用来代替a的作用域是哪一块呢就是x和y作用域的重叠部分换句话说是两者中较短的那个生命周期。又因为返回值也有生命周期a所以返回的引用在x和y作用域的重叠部分中保持有效。这就是为什么在 10.5 生命周期 Pt.1生命周期的定义与意义、借用检查器与泛型生命周期 以及本文前面都把“相同”一词放在引号里它并不是字面意义上完全相同的生命周期而是指重叠的部分。接下来看看生命周期标注如何约束对longest的调用。如果我们修改上面的例子让string1有不同的作用域并把string2改成String会发生什么fn main() { let string1 String::from(abcd); { let string2 String::from(xyz); let result longest(string1.as_str(), string2.as_str()); println!(The longest string is {result}); } } fn longesta(x: a str, y: a str) - a str { if x.len() y.len() { x } else { y } }这里string1的作用域是从第 2 行到第 8 行string2的作用域是从第 4 行到第 7 行。把它们传入longest时函数会寻找重叠部分——或者说较短的那个生命周期——也就是string2的作用域从第 4 行到第 7 行。因此a所代表的作用域是从第 4 行到第 7 行。result在内部作用域中有效也就是直到第 7 行的结束花括号为止所以代码在a范围内仍然有效。如果我改的是result的作用域呢fn main() { let string1 String::from(abcd); let result; { let string2 String::from(xyz); result longest(string1.as_str(), string2.as_str()); } println!(The longest string is {result}); } fn longesta(x: a str, y: a str) - a str { if x.len() y.len() { x } else { y } }在这种情况下string1的作用域是从第 2 行到第 9 行string2的作用域是从第 5 行到第 7 行。把它们传入longest时函数会寻找重叠部分——或者说较短的那个生命周期——也就是string2的作用域从第 5 行到第 7 行。因此函数的泛型生命周期参数a指的是从第 5 行到第 7 行的作用域返回值也应该有同样的作用域。然而接收返回值的result变量实际从第 3 行活到第 9 行超出了a所代表的作用域所以程序会报错error[E0597]: string2 does not live long enough -- src/main.rs:6:44 | 5 | let string2 String::from(xyz); | ------- binding string2 declared here 6 | result longest(string1.as_str(), string2.as_str()); | ^^^^^^^ borrowed value does not live long enough 7 | } | - string2 dropped here while still borrowed 8 | println!(The longest string is {result}); | ------ borrow later used here编译器说string2活得不够长。为了保证第 8 行打印的result有效string2必须一直保持有效直到外部作用域结束。因为函数参数和返回值使用了相同的生命周期Rust 才能指出这个问题。让我们再重复一遍本文最重要的一点a所代表的实际生命周期是x和y两个生命周期中较短的那个。