Rust —— 泛型

泛型允许我们用抽象的类型参数替代具体类型,从而编写可复用的代码。Rust 在编译时会进行单态化(Monomorphization),将泛型代码转换为具体类型的代码,因此使用泛型不会带来运行时性能损失。

1. 泛型函数

1.1 基本语法

1
2
3
4
5
6
7
8
9
10
11
fn largest<T>(list: &[T]) -> &T {
let mut largest = &list[0];

for item in list {
if item > largest {
largest = item;
}
}

largest
}

注意: 上面的代码无法编译,因为 T 没有实现比较操作符。需要添加 trait 约束。

1.2 带 trait 约束的泛型函数

1
2
3
4
5
6
7
8
9
10
11
fn largest<T: PartialOrd>(list: &[T]) -> &T {
let mut largest = &list[0];

for item in list {
if item > largest {
largest = item;
}
}

largest
}

1.3 多个泛型参数

1
2
3
fn takes_two_things<T, U>(x: T, y: U) {
// 使用不同类型的参数
}

2. 泛型结构体

2.1 单一泛型参数

1
2
3
4
5
6
7
8
9
struct Point<T> {
x: T,
y: T,
}

fn main() {
let integer = Point { x: 5, y: 10 };
let float = Point { x: 1.0, y: 4.0 };
}

注意: xy 必须是相同类型。

2.2 多个泛型参数

1
2
3
4
5
6
7
8
struct Point<T, U> {
x: T,
y: U,
}

fn main() {
let point = Point { x: 5, y: 4.0 }; // x 是 i32, y 是 f64
}

3. 泛型枚举

3.1 Option 枚举

1
2
3
4
enum Option<T> {
Some(T),
None,
}

3.2 Result 枚举

1
2
3
4
enum Result<T, E> {
Ok(T),
Err(E),
}

这两个枚举是 Rust 标准库中最常用的泛型枚举。

4. 泛型方法

4.1 为泛型结构体实现方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct Point<T> {
x: T,
y: T,
}

impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}

fn main() {
let p = Point { x: 5, y: 10 };
println!("p.x = {}", p.x());
}

说明: 需要在 impl 后声明 <T>,表示为泛型类型 Point<T> 实现方法。

4.2 为特定类型实现方法

1
2
3
4
5
impl Point<f32> {
fn distance_from_origin(&self) -> f32 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}

这个方法只对 Point<f32> 有效。

4.3 方法中的额外泛型参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct Point<X1, Y1> {
x: X1,
y: Y1,
}

impl<X1, Y1> Point<X1, Y1> {
fn mixup<X2, Y2>(self, other: Point<X2, Y2>) -> Point<X1, Y2> {
Point {
x: self.x,
y: other.y,
}
}
}

fn main() {
let p1 = Point { x: 5, y: 10.4 };
let p2 = Point { x: "Hello", y: 'c' };

let p3 = p1.mixup(p2);
println!("p3.x = {}, p3.y = {}", p3.x, p3.y); // 5, c
}

5. 泛型的性能

Rust 使用单态化在编译时将泛型代码展开为具体类型:

1
2
let integer = Some(5);
let float = Some(5.0);

编译后实际生成:

1
2
3
4
5
6
7
8
9
10
11
12
enum Option_i32 {
Some(i32),
None,
}

enum Option_f64 {
Some(f64),
None,
}

let integer = Option_i32::Some(5);
let float = Option_f64::Some(5.0);

优点: 运行时零成本抽象,性能等同于手写具体类型。

缺点: 会增加编译时间和二进制文件大小。

总结

  • 泛型函数:使用 <T> 定义类型参数,提高代码复用性
  • 泛型结构体/枚举:可以存储任意类型的数据
  • 泛型方法:在 impl<T> 中声明类型参数
  • 零成本抽象:编译时单态化,运行时无性能损失

泛型是 Rust 中实现代码复用和抽象的重要工具,配合 trait 约束可以实现强大的类型安全保证。

Hooray!泛型学习完成!!!