Skip to main content

Rust: life-time

📅 2026-04-07 ✏️ 2026-04-07 CS RUST
No related notes

1 · Rust life-time#

https://vinayakdsci.hashnode.dev/exploring-rust-lifetimes

1.1 · Borrow Checker#

本质:XOR 约束——任何实体要么可变(mutable),要么可别名(aliasable),二者不可兼得。这让编译器无需假设内存被别名引用,从而获得更多优化空间。

Borrow Checker 还强制执行对象的 lifetime:如果对象 A 持有对象 B 的非拥有引用(non-owning reference),那么 A 不能比 B 活得更久,否则 A 就持有了一个悬垂引用。

1.2 · 用 unsafe 演示 use-after-free#

用 raw pointer 构建一个简单的 fat pointer 结构体 DataBuffer

struct DataBuffer {
    data: *const f32,
    length: usize,
}

impl DataBuffer {
    fn new(sl: &[f32]) -> Self {
        Self {
            data: sl.as_ptr(),
            length: sl.len(),
        }
    }
}
  • new() 接受一个 slice 引用,提取其 raw pointer,但不拥有底层内存
  • 编译器对 raw pointer 不做 lifetime 跟踪,也不做 bounds checking

当在一个内部 scope 里重新创建 buf 并赋值给外部的 dbuffer,scope 结束后 buf 被 drop,dbuffer 就持有了悬垂指针——经典的 use-after-free

let mut dbuffer = DataBuffer::new(&buf);
{
    let buf = vec![0.0, 1.0, 2.0, 3.0];
    dbuffer = DataBuffer::new(&buf);
} // buf dropped, dbuffer 现在是悬垂指针
assert_eq!(3.0, dbuffer[3]); // UB!

1.3 · 用 Lifetime 修复#

1.3.1 · 1. 给 struct 标注 lifetime#

use std::marker::PhantomData;

struct DataBuffer<'a> {
    data: *const f32,
    length: usize,
    _marker: PhantomData<&'a f32>,
}
  • 因为 raw pointer 不携带 lifetime 信息,编译器会报 E0392: lifetime parameter 'a is never used
  • PhantomData<&'a f32> 作为零大小标记(zero-sized marker),告诉编译器这个 struct 逻辑上借用了 'a 生命周期的数据

1.3.2 · 2. 在构造函数中绑定 lifetime#

impl<'a> DataBuffer<'a> {
    fn new(sl: &'a [f32]) -> Self {
        Self {
            data: sl.as_ptr(),
            length: sl.len(),
            _marker: PhantomData,
        }
    }
}
  • sl: &'a [f32] 将参数的 lifetime 与 struct 的 'a 绑定
  • 编译器现在知道 DataBuffer 不能比传入的 slice 引用活得更久

1.3.3 · 3. Index trait 用匿名 lifetime#

impl Index<usize> for DataBuffer<'_> {
    type Output = f32;
    fn index(&self, i: usize) -> &Self::Output {
        assert!(i < self.length);
        unsafe { &*self.data.add(i) }
    }
}

1.3.4 · 效果

加上 lifetime 后,之前的 use-after-free 代码直接编译失败

error[E0597]: `buf` does not live long enough

1.4 · 核心要点

  • PhantomData pattern 是 Rust 标准库中的常见惯用法,用于让编译器追踪 raw pointer 背后的 lifetime
  • Lifetime 标注不改变运行时行为,只是给编译器提供静态分析信息
  • C 编译器信任你(会愉快地让你搬起石头砸自己的脚),Rust 编译器则通过 lifetime 系统拒绝编译不安全的代码