泛型允许我们用抽象的类型参数替代具体类型,从而编写可复用的代码。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 }; }
|
注意: x 和 y 必须是相同类型。
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 }; }
|
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. 泛型的性能
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!泛型学习完成!!!