Rust学习笔记 12:泛型
对应代码文件:src/bin/12_generics.rs
运行命令:
1 | cargo run --bin lesson12_generics |
学习目标
泛型让同一段代码适用于多种类型。它能减少重复,同时保持静态类型检查。
Rust 的泛型在编译期单态化,常见情况下不会带来运行时动态分发开销。
- 理解泛型参数
T的含义。 - 会定义泛型函数和泛型结构体。
- 知道泛型需要 trait bound 才能使用特定能力。
- 理解
Option<T>、Result<T, E>也是泛型类型。
核心概念速查
| 术语 | 基本意思 | 本节用途 |
|---|---|---|
| 泛型 generic | 把具体类型抽象成类型参数。 | fn identity<T>(value: T) -> T 可接收多种类型。 |
| 类型参数 T | 泛型中的占位类型名。 | T 不是固定名字,只是惯例。 |
| 单态化 monomorphization | 编译器为实际类型生成具体版本。 | 这是 Rust 泛型高性能的原因之一。 |
| 泛型结构体 | 字段类型带类型参数的结构体。 | Point<T> 可表示整数点或浮点点。 |
| trait bound | 限制泛型类型必须具备某些能力。 | 下一节会详细讲。 |
完整源码
1 | fn largest<T: PartialOrd + Copy>(items: &[T]) -> T { |
运行与观察
使用 cargo run --bin lesson12_generics 可以只运行本节示例。
这里的 --bin 后面写的是 Cargo.toml 中声明的目标名,不是 .rs 文件名。文件名用于组织源码,bin 名用于 Cargo 运行。
建议初学时先直接运行,再修改一两行代码观察编译器提示。Rust 的错误信息通常会指出所有权、类型或借用规则哪里不满足。
逐段解读
泛型函数
fn identity<T>(value: T) -> T 接收什么类型就返回什么类型。
泛型结构体
struct Pair<T> 用同一种 T 保存两个值。
多个泛型参数
Result<T, E> 同时有成功值类型和错误类型。
约束需求
如果要比较、打印或相加泛型值,就必须添加相应 trait bound。
专有词语详解
泛型 generic
把具体类型抽象成类型参数。
fn identity<T>(value: T) -> T 可接收多种类型。
类型参数 T
泛型中的占位类型名。
T 不是固定名字,只是惯例。
单态化 monomorphization
编译器为实际类型生成具体版本。
这是 Rust 泛型高性能的原因之一。
泛型结构体
字段类型带类型参数的结构体。
Point<T> 可表示整数点或浮点点。
trait bound
限制泛型类型必须具备某些能力。
下一节会详细讲。
初学者拓展
泛型不是“任意类型随便用”。没有约束时,你只能移动、返回或保存它,不能随便比较或打印。
T、U、E 只是类型参数名字。E 常用来表示 error 类型。
泛型能把“算法结构”从“具体数据类型”中分离出来。
当两个字段都写 T 时,它们必须是同一具体类型。需要不同类型时写 T, U。
常见误区
- 不要以为泛型函数内部自动知道
T能打印。打印需要T: Debug或T: Display。 - 如果结构体字段一个是整数、一个是浮点数,就不要都写成同一个
T。 - 泛型参数过多会降低可读性。初学阶段先保持简单。
- 泛型解决重复类型逻辑,不适合掩盖完全不同的业务概念。
进阶练习与参考答案
练习 1:identity 函数
要求:写一个返回原值的泛型函数。
参考答案:
1 | fn identity<T>(value: T) -> T { |
解释:T 由调用时传入的值推断出来。
练习 2:泛型结构体
要求:定义 Point<T> 并创建整数点和浮点点。
参考答案:
1 | struct Point<T> { |
解释:同一个结构体模板可以生成不同具体类型。
练习 3:两个类型参数
要求:定义 Pair<T, U> 保存不同类型。
参考答案:
1 | struct Pair<T, U> { |
解释:T 和 U 允许两个字段拥有不同类型。