Skip to content

泛型实战总结

> 理解泛型的单态化机制,对比 Rust 与其他语言的泛型实现,掌握泛型的性能特性。

泛型与性能:单态化

什么是单态化?

单态化(Monomorphization)是 Rust 编译器在编译时
将泛型代码转换为具体类型代码的过程。

源代码(泛型):
fn largest<T: PartialOrd>(list: &[T]) -> &T { ... }

编译后(单态化):
fn largest_i32(list: &[i32]) -> &i32 { ... }
fn largest_f64(list: &[f64]) -> &f64 { ... }
fn largest_char(list: &[char]) -> &char { ... }

单态化过程

┌─────────────────────────────────────────────────────┐
│              Rust 泛型单态化                         │
├─────────────────────────────────────────────────────┤
│                                                     │
│  编译时:                                            │
│  1. 类型推断:确定所有泛型参数的具体类型            │
│  2. 代码生成:为每个类型组合生成专用代码            │
│  3. 优化:编译器可以进一步优化专用代码              │
│                                                     │
│  运行时:                                            │
│  • 没有泛型类型信息                                  │
│  • 没有虚函数调用开销                               │
│  • 与手写专用代码完全相同                           │
│                                                     │
│  优点:                                              │
│  ✓ 零运行时开销                                      │
│  ✓ 类型安全                                          │
│  ✓ 代码优化更好                                      │
│                                                     │
│  缺点:                                              │
│  ✗ 代码膨胀(每个类型组合一份代码)                 │
│  ✗ 编译时间增加                                      │
│                                                     │
└─────────────────────────────────────────────────────┘

单态化示例

rust
// 泛型代码
fn process<T: Clone + Display>(items: &[T]) -> Vec<T> {
    items.iter().map(|item| item.clone()).collect()
}

fn main() {
    // 编译器会为每个类型生成专用版本
    let ints: Vec<i32> = process(&[1, 2, 3]);
    let floats: Vec<f64> = process(&[1.0, 2.0, 3.0]);
    let strings: Vec<String> = process(&["a", "b"]);

    // 生成的代码类似于:
    // fn process_i32(items: &[i32]) -> Vec<i32> { ... }
    // fn process_f64(items: &[f64]) -> Vec<f64> { ... }
    // fn process_String(items: &[&str]) -> Vec<String> { ... }
}
▶ Run

Rust vs 其他语言

┌─────────────────────────────────────────────────────┐
│           泛型实现方式对比                           │
├─────────────────────────────────────────────────────┤
│                                                     │
│  Rust(单态化)                                     │
│  ├── 编译时生成专用代码                             │
│  ├── 运行时零开销                                   │
│  ├── 代码可能膨胀                                   │
│  └── 适合系统编程                                   │
│                                                     │
│  Java/Go(类型擦除)                                │
│  ├── 编译时擦除类型信息                             │
│  ├── 运行时类型检查                                 │
│  ├── 代码不膨胀                                     │
│  └── 有一定运行时开销                               │
│                                                     │
│  C++(模板实例化)                                  │
│  ├── 类似 Rust 的单态化                            │
│  ├── 编译时展开                                     │
│  ├── 零运行时开销                                   │
│  └── 错误信息可能难懂                               │
│                                                     │
└─────────────────────────────────────────────────────┘



---

## 小结

- 单态化在编译时为每个具体类型生成专用代码
- Rust 泛型实现零运行时开销,性能等同于手写代码
- 与 Java/Go 的类型擦除相比,Rust 更适合系统编程
- 单态化可能导致代码膨胀,需要权衡
- 编译时优化使泛型代码可以进一步内联和优化

## 练习题

详见:[练习题](../../exercises/15-generics)