Rust数据结构源码实现
本文最后更新于 2026年4月13日 下午
解析Rust部分数据结构的源码实现
需要注意的是,为了方便,对源码的一些实现有改写
Vec
从单纯的数据结构设计上,大概如下
1 | |
其中的 _marker: PhantomData<T> 是在逻辑上标注对 T 的所有权,方便编译器做一些检查;Cap 会根据不通平台条件编译为不同范围的usize
new
1 | |
这里有一些有意思的,首先是会有一个对齐的检查,随后创建一个满足对齐的悬垂指针,所以其实还没有分配堆内存。
with_capacity
1 | |
前面就是一些封装,具体后面的部分:AllocInit::Uninitialized 规定使用非初始化的内存分配,会快一点;随后计算所需的内存大小并分配,将得到的内存地址做包装后返回。
push
1 | |
因为内存是未初始化的,所以会使用 ptr::write 直接向内存写数据。我们具体关注扩容逻辑,
$$
\text{new_cap} = max(\text{old_cap} * 2, \text{old_cap} + \text{needed}, \text{min_non_zero_cap})
$$
指数倍增,并且会使用类型大小来选择保底扩容大小;具体的内存分配部分,使用alloc提供的能力,尽可能的进行原地扩展(不保证)。
get
有趣的是,rust标准库对切片实现了 get,而 Vec 又可以自动 Deref 为切片,所以复用了这一部分能力
remove
读出其中的值,并批量移动内存数据
insert
先判断扩容,然后移动,最后写入值
LinkedList
1 | |
普普通通毫无亮点口牙!
new
1 | |
太棒了,简洁易懂
push_back
1 | |
在堆上创建 Node<T>,随后将带有所有权的 Box 转化为 NonNull;push_back_node 更是极为显然的逻辑。
pop_back
其实可以略了
HashMap
1 | |
| 字段 | 作用 | 深度解析 |
|---|---|---|
bucket_mask |
快速取模 | 桶的数量永远是 $2^n$,所以 hash & bucket_mask 效果等同于 hash % capacity,但位运算速度极快。 |
growth_left |
扩容阈值 | 记录还能插入多少元素。当它降到 0 时,触发 rehash 扩容,防止哈希冲突过多导致性能下降。 |
ctrl |
标记控制区起点 | 使用SIMD加速哈希匹配判断 |
with_capacity
1 | |
内存刚申请下来是脏的,需要先把所有的控制字节设置为0xFF;在申请内存时,首先精确得到layout和控制区偏移量,随后如果分配器给出的内存超过实际申请,会进行自动扩容来利用这部分空间;最后返回的ctrl指针是控制区的起点。
insert
1 | |
这部分是最有趣的,常规的算法会在hash后拿到桶的下标,并遍历匹配,这其中频繁的内存读取消耗巨大;而源码的算法是先通过控制位与哈希值的高七位做匹配,这可以借助SIMD实现批量匹配,只有匹配到的节点才会去尝试检查。太酷了!