---
title: 基础类型与内存布局
url: https://doc.liz6.com/rust/02-type-system/01-primitive-types-and-memory-layout
locale: zh
area: rust
tags:
- rust
- 类型系统
date: 2026-06-30
modified: 2026-06-30
description: Rust 的每个类型都有精确的内存布局——整数和浮点按位宽对齐,struct 有 padding,零大小类型(ZST)占 0 字节,niche optimization 让 Option 和 bool 一样大(因为 bool 只有 0/1,编译器用 2 的位模式表示 None)。理解布局是理解为什么 Rust 没有"…
---

# 基础类型与内存布局

> Rust 的每个类型都有精确的内存布局——整数和浮点按位宽对齐,struct 有 padding,零大小类型(ZST)占 0 字节,niche optimization 让 `Option<bool>` 和 `bool` 一样大(因为 bool 只有 0/1,编译器用 2 的位模式表示 None)。理解布局是理解为什么 Rust 没有"装箱开销"的前提。

## 标量类型: 不仅是"和 C 差不多"

Rust 的整数类型和 C 看起来一样——`i32`, `u64` 等等——但语义上有重要区别：

```rust
let x: u8 = 255;
// x + 1: debug mode → panic!("attempt to add with overflow")
//        release mode → wraps to 0 (two's complement, 无未定义行为)

// 三种显式溢出处理:
255u8.checked_add(1)      // None (返回 Option, 不 panic)
255u8.wrapping_add(1)     // 0 (明确要 wrap)
255u8.saturating_add(1)   // 255 (饱和运算)
```

C 中 signed integer overflow 是 UB。Rust 中即使 release mode 的 wrap 也是定义好的行为——不是 UB。但 debug mode 的 panic 让你在测试中暴露溢出 bug。

## 类型大小和对齐

每种类型有确定的 `size_of` 和 `align_of`，不依赖平台（除了 `isize/usize`）：

```rust
use std::mem::{size_of, align_of};

size_of::<u8>()     // 1
size_of::<i64>()    // 8
size_of::<bool>()   // 1 (不是 1 bit! 内存最小寻址单位是 byte)
size_of::<char>()   // 4 (Unicode scalar value, 不是 code point)
size_of::<()>()     // 0 (unit type, ZST)
size_of::<&i32>()   // 8 (64-bit) or 4 (32-bit)
```

`bool` 占 1 byte 的原因：CPU 指令集寻址的最小单位是 byte。Rust 不允许取 `bool` 的某一位的地址。如果需要紧凑存储 bool 数组，用 `bitvec` crate 或 `Vec<u64>` 手动 bit-packing。

## char: 4 bytes = 一个 Unicode scalar value

```rust
let c: char = 'あ';                  // U+3042, 3 bytes in UTF-8, 4 bytes as char
size_of::<char>()                    // 4

// char 和 string 的关系:
let s = "あ";                        // &str, 3 bytes: [E3, 81, 82]
let c = 'あ';                        // char, 4 bytes: 0x00003042
```

`char` 代表一个 Unicode scalar value（0x0000~0xD7FF, 0xE000~0x10FFFF），不是"一个字符"（user-perceived character 可能是多个 scalar values 组合，如 é = e + ́）。这与 Go 的 `rune`（=int32）类似。

## 复合类型的内存布局

```rust
#[repr(C)]
struct C { a: u8, b: u32, c: u16 }
// memory: [a:1B][padding:3B][b:4B][c:2B][padding:2B] = 12 bytes
// C ABI: 字段按声明顺序, 自动 padding 满足对齐要求

struct Rust { a: u8, b: u32, c: u16 }
// 默认 layout: 编译器可以重排字段以优化大小!
// 可能排列为: [b:4B][c:2B][a:1B][padding:1B] = 8 bytes
```

默认 Rust layout 不保证顺序——编译器可以 reorder 字段来减小 padding。如果需要与 C 互操作或保证稳定布局，必须 `#[repr(C)]`。

## 数组: 大小是类型的一部分

```rust
let arr1: [i32; 3] = [1, 2, 3];     // 编译期固定大小
let arr2: [i32; 1000] = [0; 1000];   // 栈上 4000 bytes!

fn take_arr(arr: [i32; 1000]) { ... }  // 按值传递: 拷贝整个 4000 bytes
fn take_slice(arr: &[i32]) { ... }     // 引用传递: 只拷贝 fat pointer (16 bytes)
```

数组按值传递会复制整个数组——因为 Rust 的 move semantics 对数组是逐元素复制。对于大数组，总是传 `&[T]` 或 `&[T; N]`。

## ZST (Zero-Sized Types): 编译时隐形的魔法

```rust
struct NoData;                       // 0 bytes
let x = NoData;                      // 不占任何栈空间
let arr: [NoData; 1_000_000];        // 0 bytes! 没有分配任何内存

// ZST 的实用价值: HashMap 的 key
use std::collections::HashSet;
let set: HashSet<NoData> = ...;      // 只区分"存在"和"不存在"
```

编译器在生成代码时完全省略 ZST 的存储和传递——它们不存在于运行时的任何地方，只有类型层面的意义。

## Niche Optimization: 零成本的 Option

Rust 编译器利用"不可能的比特模式"来节省 enum 的空间：

```rust
size_of::<Option<bool>>()            // 1 byte, not 2!
// bool 只有 0x00 (false) 和 0x01 (true) 两个有效值
// 编译器用 0x02 表示 None → 不需要额外的 discriminant field

size_of::<Option<&i32>>()            // 8 bytes, not 16!
// &T 保证 non-null → 编译器用 nullptr 编码 None
// 解引用 Option<&T> 时: 先检查是否为 null → None → panic/return None
// → Some 则就是正常引用

size_of::<Option<Box<i32>>>()        // 8 bytes — Box 内部是 non-null ptr
size_of::<Option<Option<&i32>>>()    // 8 bytes — 两个 niche: nullptr 和 ...?
// 实际上 Option<&T> 只有一个 niche (null)
// Option<Option<&T>> 需要 2 niche values → 16 bytes (two words)
```

这个优化是 Rust 能在系统级安全中保持零开销的关键——你不需要为 `Option<&T>` 付出额外的内存或运行时代价。

## 参考

- **Rust Reference**: Type Layout (section "Data Layout")
- **Rustonomicon**: Exotic Sizes, repr, alignment
- **RFC**: RFC 139 (niche optimization)

*Keywords: integer types, alignment, repr(C), ZST, niche optimization, Option<&T>, layout, size_of, align_of*
