泛型基础
> 理解泛型的概念和价值,掌握泛型函数的基本语法,了解泛型的单态化机制。
为什么需要泛型?
泛型语法
概念名称: 泛型允许编写适用于多种类型的代码。
语法结构:
┌──────────────────────────────────────┐
│ 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
▶ Runfn identity<T>(x: T) -> T {
x
}
fn main() {
let a = identity(5); // i32
let b = identity("hi"); // &str
println!("{} {}", a, b);
}代码重复问题
rust
▶ Run// 问题:为每种类型写相同的逻辑
// 用于 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
}
// 问题:逻辑完全相同,只是类型不同!泛型的解决方案
rust
▶ Run// 使用泛型:一套代码,适用于所有可比较的类型
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));
}泛型的核心优势
┌─────────────────────────────────────────────────────┐
│ 泛型的优势 │
├─────────────────────────────────────────────────────┤
│ │
│ 1. 代码复用 │
│ • 一套逻辑适用于多种类型 │
│ • 减少代码重复 │
│ • 易于维护(修改一处即可) │
│ │
│ 2. 类型安全 │
│ • 编译时类型检查 │
│ • 运行时无额外开销 │
│ • 错误早发现 │
│ │
│ 3. 零成本抽象 │
│ • 编译时单态化(monomorphization) │
│ • 与手写专用代码性能相同 │
│ • 无运行时泛型开销 │
│ │
│ 4. 表达力强 │
│ • 精确表达类型关系 │
│ • 约束条件清晰 │
│ • API 设计更灵活 │
│ │
└─────────────────────────────────────────────────────┘
---
## 小结
- 泛型允许编写适用于多种类型的代码,减少重复
- `fn foo<T>(x: T)` 定义泛型函数,编译器自动推断具体类型
- 泛型提供代码复用、类型安全、零成本抽象三大优势
- 单态化在编译时为每个具体类型生成专用代码
- 泛型约束(`T: Trait`)限制泛型参数的能力
## 练习题
详见:[练习题](../../exercises/15-generics)