生命周期 #

一、生命周期概述 #

生命周期是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有三条生命周期省略规则:

  1. 每个引用参数都获得一个生命周期参数
  2. 如果只有一个输入生命周期,它被赋给所有输出生命周期
  3. 如果有多个输入生命周期但其中一个是 &self&mut selfself 的生命周期被赋给所有输出生命周期

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