6.2 泛型语法与泛型函数/结构体
泛型(Generics)是 Rust 支持代码复用和类型安全的重要机制。通过泛型,你可以编写适用于多种类型的函数、结构体或枚举,而无需为每种类型重复实现逻辑。Rust 的泛型在编译期完成类型检查和单态化(monomorphization),因此不会带来运行时性能开销。
泛型函数
考虑一个返回两个值中较大者的函数。若不使用泛型,需为每种类型分别实现:
fn max_i32(x: i32, y: i32) -> i32 { /* ... */ }
fn max_f64(x: f64, y: f64) -> f64 { /* ... */ }
使用泛型后,可统一为:
fn max<T>(x: T, y: T) -> T {
if x > y { x } else { y }
}
但此代码无法直接编译,因为并非所有类型 T 都支持 > 比较。我们需要通过 trait bound 约束 T 必须实现 PartialOrd trait(后续章节将详细介绍)。暂且假设我们处理的是已知支持比较的类型。
调用时,Rust 通常能自动推断类型:
let a = max(1, 3); // T 推断为 i32
let b = max(2.5, 1.8); // T 推断为 f64
也可显式指定类型参数:
let c = max::<i32>(1, 3);
泛型结构体
结构体也可以使用泛型,以存储任意类型的字段。
例如,定义一个持有单个值的“包裹”:
struct Wrapper<T> {
value: T,
}
let int_wrapper = Wrapper { value: 42 };
let str_wrapper = Wrapper { value: String::from("hello") };
你还可以为泛型结构体实现方法。方法定义中需重复泛型参数:
impl<T> Wrapper<T> {
fn new(value: T) -> Self {
Wrapper { value }
}
fn get_value(&self) -> &T {
&self.value
}
}
这里 impl<T> 表示该实现块适用于任意类型 T。Self 是 Wrapper<T> 的别名。
泛型枚举
标准库中的 Option<T> 和 Result<T, E> 就是泛型枚举的典型例子:
enum Option<T> {
Some(T),
None,
}
这使得 Option 可以安全地表示任何类型的“可能存在”的值。
多个泛型参数
Rust 支持多个泛型参数。例如,HashMap<K, V> 使用两个:
struct Pair<K, V> {
key: K,
value: V,
}
let p = Pair { key: "age", value: 30 };
在 impl 块中同样需要声明所有泛型:
impl<K, V> Pair<K, V> {
fn key(&self) -> &K {
&self.key
}
}
性能与单态化
Rust 在编译时会对每个具体类型生成独立的函数或结构体实例。例如,max(1, 2) 和 max(1.0, 2.0) 会分别生成 max::<i32> 和 max::<f64> 的代码。这种单态化确保了泛型代码与手写特化版本具有相同的运行效率。
小结
泛型使 Rust 代码更具通用性和复用性,同时保持零成本抽象。通过在函数、结构体和枚举中使用类型参数,你可以编写一次逻辑,应用于多种类型。结合后续将介绍的 trait 约束,泛型将成为构建灵活、安全且高效抽象的核心工具。