9.1 布局

Vec 的内存布局

译文 · 基于 The Rustonomicon

布局

原文链接: https://doc.rust-lang.org/nomicon/vec/vec-layout.html

  首先,我们需要确定 struct 布局。Vec 有三部分:指向分配的指针、分配的大小、已初始化元素的数量。

  直观上,我们只需这种设计:

pub struct Vec<T> {
    ptr: *mut T,
    cap: usize,
    len: usize,
}

  这确实能编译。不幸的是,它会过于严格。编译器会给出过于严格的 variance。于是 &Vec<&'static str> 不能用在需要 &Vec<&'a str> 的地方。详见所有权与 lifetime 章节。

  如所有权章所见,标准库在拥有分配时用 Unique<T> 代替 *mut T。Unique 不稳定,因此我们尽可能不用。

  简要回顾,Unique 是围绕 raw pointer 的包装,声明:

  • 我们对 T 是协变的(covariant)
  • 我们可能拥有类型 T 的值(与此例无关,但见 PhantomData 章节 了解真实 std::vec::Vec<T> 为何需要)
  • 若 T 是 Send/Sync,则我们是 Send/Sync
  • 我们的指针永不为 null(因此 Option<Vec<T>> 是 null 指针优化)

  我们可以在稳定 Rust 中实现上述全部要求。为此,不用 Unique<T>,而用 NonNull<T>——另一个 raw pointer 包装,给我们上述性质中的两条:对 T 协变,且声明永不为 null。若 T 是 Send/Sync 则实现 Send/Sync,效果与 Unique<T> 相同:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
use std::ptr::NonNull;

pub struct Vec<T> {
    ptr: NonNull<T>,
    cap: usize,
    len: usize,
}

unsafe impl<T: Send> Send for Vec<T> {}
unsafe impl<T: Sync> Sync for Vec<T> {}
# fn main() {}
最后修改 August 11, 2026: 更新 (70a5af133)