Skip to content

泛型基础

> 理解泛型的概念和价值,掌握泛型函数的基本语法,了解泛型的单态化机制。

为什么需要泛型?

泛型语法

概念名称: 泛型允许编写适用于多种类型的代码。

语法结构:
┌──────────────────────────────────────┐
│  fn 函数名<T>(参数: T) -> T          │
│         ↑      ↑                     │
│         类型参数  使用泛型            │
│                                       │
│  fn identity<T>(x: T) -> T { x }     │
│                                       │
│  泛型约束:                            │
│  fn foo<T: Trait>(x: T)              │
│  fn foo<T>(x: T) where T: Trait      │
│                                       │
│  结构体泛型:                          │
│  struct Point<T> { x: T, y: T }      │
└──────────────────────────────────────┘

最简示例

rust
fn identity<T>(x: T) -> T {
    x
}

fn main() {
    let a = identity(5);      // i32
    let b = identity("hi");   // &str
    println!("{} {}", a, b);
}
▶ Run

代码重复问题

rust
// 问题:为每种类型写相同的逻辑

// 用于 i32
fn largest_i32(list: &[i32]) -> i32 {
    let mut largest = list[0];
    for &item in list {
        if item > largest {
            largest = item;
        }
    }
    largest
}

// 用于 f64
fn largest_f64(list: &[f64]) -> f64 {
    let mut largest = list[0];
    for &item in list {
        if item > largest {
            largest = item;
        }
    }
    largest
}

// 用于 char
fn largest_char(list: &[char]) -> char {
    let mut largest = list[0];
    for &item in list {
        if item > largest {
            largest = item;
        }
    }
    largest
}

// 问题:逻辑完全相同,只是类型不同!
▶ Run

泛型的解决方案

rust
// 使用泛型:一套代码,适用于所有可比较的类型
fn largest<T: PartialOrd>(list: &[T]) -> &T {
    let mut largest = &list[0];
    for item in list {
        if item > largest {
            largest = item;
        }
    }
    largest
}

fn main() {
    // 用于 i32
    let numbers = vec![34, 50, 25, 100, 65];
    println!("最大的数字:{}", largest(&numbers));

    // 用于 f64
    let floats = vec![1.5, 3.14, 2.71, 0.5];
    println!("最大的浮点数:{}", largest(&floats));

    // 用于 char
    let chars = vec!['y', 'm', 'a', 'q'];
    println!("最大的字符:{}", largest(&chars));

    // 用于 String
    let strings = vec![String::from("apple"), String::from("zebra")];
    println!("最大的字符串:{}", largest(&strings));
}
▶ Run

泛型的核心优势

┌─────────────────────────────────────────────────────┐
│              泛型的优势                              │
├─────────────────────────────────────────────────────┤
│                                                     │
│  1. 代码复用                                         │
│     • 一套逻辑适用于多种类型                        │
│     • 减少代码重复                                  │
│     • 易于维护(修改一处即可)                      │
│                                                     │
│  2. 类型安全                                         │
│     • 编译时类型检查                                │
│     • 运行时无额外开销                              │
│     • 错误早发现                                    │
│                                                     │
│  3. 零成本抽象                                       │
│     • 编译时单态化(monomorphization)              │
│     • 与手写专用代码性能相同                        │
│     • 无运行时泛型开销                              │
│                                                     │
│  4. 表达力强                                         │
│     • 精确表达类型关系                              │
│     • 约束条件清晰                                  │
│     • API 设计更灵活                                │
│                                                     │
└─────────────────────────────────────────────────────┘



---

## 小结

- 泛型允许编写适用于多种类型的代码,减少重复
- `fn foo<T>(x: T)` 定义泛型函数,编译器自动推断具体类型
- 泛型提供代码复用、类型安全、零成本抽象三大优势
- 单态化在编译时为每个具体类型生成专用代码
- 泛型约束(`T: Trait`)限制泛型参数的能力

## 练习题

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