生命周期 #
一、生命周期概述 #
生命周期是Rust用来确保引用始终有效的机制。它描述了引用有效的作用域范围。
1.1 为什么需要生命周期 #
rust
fn main() {
let r;
{
let x = 5;
r = &x; // 错误:x 的生命周期不够长
}
// println!("{}", r); // r 引用已释放的 x
}
1.2 生命周期的作用 #
- 确保引用始终有效
- 防止悬垂引用
- 编译时检查
二、生命周期标注 #
2.1 语法 #
生命周期参数以单引号开头,通常使用小写字母:
rust
&i32 // 普通引用
&'a i32 // 带有显式生命周期的引用
&'a mut i32 // 带有显式生命周期的可变引用
2.2 函数中的生命周期 #
rust
fn main() {
let string1 = String::from("abcd");
let string2 = "xyz";
let result = longest(string1.as_str(), string2);
println!("最长的字符串是 {}", result);
}
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
2.3 生命周期标注的含义 #
生命周期标注不改变引用的生命周期,只是描述多个引用之间的关系:
rust
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
// 返回值的生命周期与参数中较短的那个相同
if x.len() > y.len() {
x
} else {
y
}
}
三、生命周期示例 #
3.1 正确使用 #
rust
fn main() {
let string1 = String::from("long string");
{
let string2 = String::from("xyz");
let result = longest(string1.as_str(), string2.as_str());
println!("最长的字符串是 {}", result);
}
}
3.2 错误示例 #
rust
fn main() {
let string1 = String::from("long string");
let result;
{
let string2 = String::from("xyz");
result = longest(string1.as_str(), string2.as_str());
}
// println!("最长的字符串是 {}", result); // 错误:string2 已释放
}
四、结构体中的生命周期 #
4.1 存储引用的结构体 #
rust
struct ImportantExcerpt<'a> {
part: &'a str,
}
fn main() {
let novel = String::from("Call me Ishmael. Some years ago...");
let first_sentence = novel.split('.').next().expect("Could not find a '.'");
let excerpt = ImportantExcerpt {
part: first_sentence,
};
println!("摘录: {}", excerpt.part);
}
4.2 结构体方法 #
rust
struct ImportantExcerpt<'a> {
part: &'a str,
}
impl<'a> ImportantExcerpt<'a> {
fn level(&self) -> i32 {
3
}
fn announce_and_return_part(&self, announcement: &str) -> &str {
println!("公告: {}", announcement);
self.part
}
}
fn main() {
let novel = String::from("Hello. World.");
let first = novel.split('.').next().unwrap();
let excerpt = ImportantExcerpt { part: first };
println!("级别: {}", excerpt.level());
println!("部分: {}", excerpt.announce_and_return_part("注意"));
}
五、生命周期省略 #
5.1 省略规则 #
Rust有三条生命周期省略规则:
- 每个引用参数都获得一个生命周期参数
- 如果只有一个输入生命周期,它被赋给所有输出生命周期
- 如果有多个输入生命周期但其中一个是
&self或&mut self,self的生命周期被赋给所有输出生命周期
5.2 示例 #
rust
// 省略前
fn first_word<'a>(s: &'a str) -> &'a str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
// 省略后(编译器自动推断)
fn first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
5.3 需要显式标注的情况 #
rust
// 需要显式标注
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
六、静态生命周期 #
6.1 'static 生命周期 #
'static 表示整个程序运行期间都有效:
rust
fn main() {
// 字符串字面量具有 'static 生命周期
let s: &'static str = "I have a static lifetime.";
println!("{}", s);
}
6.2 使用场景 #
rust
fn main() {
// 静态变量
static GREETING: &str = "Hello, world!";
println!("{}", GREETING);
}
6.3 注意事项 #
rust
// 错误:不要滥用 'static
// fn get_string() -> &'static str {
// let s = String::from("hello");
// &s // 错误:局部变量不能有 'static 生命周期
// }
// 正确
fn get_static_string() -> &'static str {
"hello" // 字符串字面量
}
七、生命周期子类型化 #
7.1 生命周期协变 #
更长的生命周期可以替代较短的生命周期:
rust
fn main() {
let string1 = String::from("long string");
let string2 = String::from("short");
// 'long 可以替代 'short
let result: &str = longest(&string1, &string2);
println!("{}", result);
}
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
八、生命周期约束 #
8.1 where 子句 #
rust
fn main() {
let string1 = String::from("abcd");
let string2 = String::from("xyz");
let result = longest_with_announcement(string1.as_str(), string2.as_str(), "比较中");
println!("{}", result);
}
fn longest_with_announcement<'a, T>(
x: &'a str,
y: &'a str,
ann: T,
) -> &'a str
where
T: std::fmt::Display,
{
println!("公告: {}", ann);
if x.len() > y.len() {
x
} else {
y
}
}
8.2 生命周期边界 #
rust
struct Wrapper<'a, T: 'a> {
reference: &'a T,
}
fn main() {
let value = 42;
let wrapper = Wrapper { reference: &value };
println!("{}", wrapper.reference);
}
九、常见模式 #
9.1 返回引用 #
rust
struct Parser<'a> {
input: &'a str,
}
impl<'a> Parser<'a> {
fn new(input: &'a str) -> Self {
Parser { input }
}
fn peek(&self) -> Option<char> {
self.input.chars().next()
}
fn consume(&mut self) -> Option<char> {
let ch = self.input.chars().next();
if let Some(c) = ch {
self.input = &self.input[c.len_utf8()..];
}
ch
}
}
fn main() {
let input = "hello";
let mut parser = Parser::new(input);
println!("peek: {:?}", parser.peek());
println!("consume: {:?}", parser.consume());
println!("peek: {:?}", parser.peek());
}
9.2 多生命周期参数 #
rust
struct Context<'s, 'c> {
source: &'s str,
config: &'c str,
}
impl<'s, 'c> Context<'s, 'c> {
fn new(source: &'s str, config: &'c str) -> Self {
Context { source, config }
}
fn get_source(&self) -> &'s str {
self.source
}
fn get_config(&self) -> &'c str {
self.config
}
}
fn main() {
let source = "source data";
let config = "config data";
let ctx = Context::new(source, config);
println!("source: {}", ctx.get_source());
println!("config: {}", ctx.get_config());
}
十、实践示例 #
10.1 文本解析器 #
rust
struct TextParser<'a> {
text: &'a str,
position: usize,
}
impl<'a> TextParser<'a> {
fn new(text: &'a str) -> Self {
TextParser { text, position: 0 }
}
fn remaining(&self) -> &'a str {
&self.text[self.position..]
}
fn consume_while<F>(&mut self, predicate: F) -> &'a str
where
F: Fn(char) -> bool,
{
let start = self.position;
while let Some(c) = self.remaining().chars().next() {
if predicate(c) {
self.position += c.len_utf8();
} else {
break;
}
}
&self.text[start..self.position]
}
fn skip_whitespace(&mut self) {
self.consume_while(|c| c.is_whitespace());
}
fn next_word(&mut self) -> Option<&'a str> {
self.skip_whitespace();
if self.position < self.text.len() {
Some(self.consume_while(|c| !c.is_whitespace()))
} else {
None
}
}
}
fn main() {
let text = "hello world from rust";
let mut parser = TextParser::new(text);
while let Some(word) = parser.next_word() {
println!("单词: {}", word);
}
}
10.2 缓存结构 #
rust
struct Cache<'a, T> {
data: &'a [T],
}
impl<'a, T: std::fmt::Debug> Cache<'a, T> {
fn new(data: &'a [T]) -> Self {
Cache { data }
}
fn get(&self, index: usize) -> Option<&'a T> {
self.data.get(index)
}
fn first(&self) -> Option<&'a T> {
self.data.first()
}
fn last(&self) -> Option<&'a T> {
self.data.last()
}
}
fn main() {
let numbers = vec![1, 2, 3, 4, 5];
let cache = Cache::new(&numbers);
println!("第一个: {:?}", cache.first());
println!("最后一个: {:?}", cache.last());
println!("索引2: {:?}", cache.get(2));
}
十一、总结 #
本章学习了:
- 生命周期的概念和作用
- 生命周期标注语法
- 函数中的生命周期
- 结构体中的生命周期
- 生命周期省略规则
- 静态生命周期
- 生命周期约束
生命周期是Rust保证引用安全的核心机制。下一章,我们将学习运算符。
最后更新:2026-03-27