Skip to content

生命周期实战总结

> 综合运用生命周期知识,通过实战示例巩固引用有效范围的核心技能。

完整示例

示例 1:文档片段系统

rust
/// 文档片段,引用原文的一部分
#[derive(Debug)]
struct Excerpt<'a> {
    text: &'a str,
    start: usize,
    end: usize,
}

impl<'a> Excerpt<'a> {
    /// 创建新的片段
    fn new(text: &'a str, start: usize, end: usize) -> Self {
        Excerpt { text, start, end }
    }

    /// 获取片段内容
    fn content(&self) -> &str {
        &self.text[self.start..self.end]
    }

    /// 获取上下文(前后各扩展 n 个字符)
    fn with_context(&self, n: usize) -> &str {
        let start = self.start.saturating_sub(n);
        let end = (self.end + n).min(self.text.len());
        &self.text[start..end]
    }
}

fn main() {
    let document = String::from("Rust is a systems programming language that is blazingly fast and safe.");

    // 创建引用 document 的片段
    let excerpt = Excerpt::new(&document, 0, 41);

    println!("原文:{}", document);
    println!("片段:{}", excerpt.content());
    println!("上下文:{}", excerpt.with_context(5));
}
▶ Run

示例 2:引用计数器

rust
/// 带有标签的引用计数器
#[derive(Debug)]
struct LabelRef<'a, T> {
    label: &'a str,
    data: &'a T,
}

impl<'a, T> LabelRef<'a, T> {
    fn new(label: &'a str, data: &'a T) -> Self {
        LabelRef { label, data }
    }

    fn get(&self) -> &T {
        self.data
    }

    fn label(&self) -> &str {
        self.label
    }

    fn print(&self)
    where
        T: std::fmt::Display,
    {
        println!("{}: {}", self.label, self.data);
    }
}

fn main() {
    let value = 42;
    let labeled = LabelRef::new("answer", &value);

    labeled.print();  // answer: 42
    println!("Label: {}", labeled.label());
    println!("Value: {}", labeled.get());
}
▶ Run

示例 3:多生命周期示例

rust
/// 比较两个文本的差异
struct TextDiff<'a, 'b> {
    original: &'a str,
    modified: &'b str,
}

impl<'a, 'b> TextDiff<'a, 'b> {
    fn new(original: &'a str, modified: &'b str) -> Self {
        TextDiff { original, modified }
    }

    // 返回original 的引用(生命周期'a)
    fn get_original(&self) -> &'a str {
        self.original
    }

    // 返回modified 的引用(生命周期'b)
    fn get_modified(&self) -> &'b str {
        self.modified
    }

    // 返回较短的生命周期
    fn get_shorter(&self) -> &str {
        if self.original.len() < self.modified.len() {
            self.original  // 返回'a
        } else {
            self.modified  // 返回'b
        }
    }
}

fn main() {
    let original = String::from("Hello, World!");
    {
        let modified = String::from("Hello, Rust!");

        let diff = TextDiff::new(&original, &modified);

        println!("Original: {}", diff.get_original());
        println!("Modified: {}", diff.get_modified());
        println!("Shorter: {}", diff.get_shorter());

    }  // modified 在这里失效
       // diff 也必须在这之前失效

    // original 仍然有效
    println!("Original still valid: {}", original);
}
▶ Run

常见错误

错误 1:结构体缺少生命周期标注

rust
// ❌ 错误
// struct Excerpt {
//     part: &str,  // E0106: missing lifetime specifier
// }

// ✅ 正确
struct Excerpt<'a> {
    part: &'a str,
}
▶ Run

错误 2:返回悬垂引用

rust
// ❌ 错误
// fn create_dangle() -> &str {
//     let s = String::from("hello");
//     &s  // E0515: returns a reference to data owned by current function
// }

// ✅ 正确:返回所有权
fn create_no_dangle() -> String {
    String::from("hello")
}
▶ Run

错误 3:生命周期不匹配

rust
// ❌ 错误
// fn longest(x: &str, y: &str) -> &str {
//     if x.len() > y.len() { x } else { y }
// }
// E0106: missing lifetime specifier

// ✅ 正确
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}
▶ Run

错误 4:引用比数据活得久

rust
// ❌ 错误
// fn main() {
//     let reference: &i32;
//     {
//         let value = 5;
//         reference = &value;  // value 的生命周期比 reference 短
//     }
//     println!("{}", reference);  // E0597: value does not live long enough
// }

// ✅ 正确
fn main() {
    let value = 5;
    let reference = &value;
    println!("{}", reference);
}
▶ Run

调试技巧

显式标注帮助理解

rust
// 当编译器报错时,添加显式标注有助于理解
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    // 'a 表示:返回的引用生命周期不能超过 x 和 y
    if x.len() > y.len() {
        x
    } else {
        y
    }
}
▶ Run

理解错误信息

典型错误信息分析:

error[E0597]: `x` does not live long enough
  |
5 |     let r = &x;
  |         -   ^^ `x` dropped here while still borrowed
  |         |
  |         borrow later used here

解释:
• `x` does not live long enough: x 的生命周期不够长
• `x` dropped here: x 在这里被释放
• borrow later used here: 但引用在这里还被使用

修复:确保引用的生命周期不超过其指向数据

练习

练习 1:基本生命周期标注

为以下结构体添加正确的生命周期标注:

rust
struct Reference {
    data: &i32,
}
▶ Run

练习 2:返回较短字符串

编写函数,返回两个字符串中较短的一个:

rust
fn shortest(x: &str, y: &str) -> &str {
    // 实现
}
▶ Run

练习 3:修复错误

找出并修复以下代码的错误:

rust
fn get_first(s: &str) -> &str {
    &s[0..1]
}

struct Holder {
    value: &str,
}
▶ Run

小结

生命周期核心概念

概念说明
生命周期引用有效的范围
'a 语法生命周期参数标注
省略规则编译器自动推断
'static整个程序运行期间
约束关系'a: 'b 表示'a 包含 'b

省略规则总结

场景规则
单参数输入生命周期赋值给输出
多参数无返回每个参数独立生命周期
方法&self 生命周期赋值给输出

关键要点

  1. 生命周期防止悬垂引用,确保内存安全
  2. 大多数情况可省略,编译器自动推断
  3. 结构体引用字段必须标注生命周期
  4. 'static 表示永久有效,但不要轻易使用
  5. 理解错误信息,有助于正确标注

小结

本章我们学习了:

  • 生命周期的本质和内存布局分析
  • 生命周期标注语法和省略规则
  • 结构体中的生命周期应用
  • 'static 和生命周期约束的高级用法
  • 实战案例:文档片段系统和零拷贝解析器

练习题

详见:练习题