泛型
- 类似函数的参数,这是一种类型参数
- 与 TS 不同的是,Rust 必须为函数泛型参数指定
trait,也就是指定泛型的能力,才可以使用参数的方法(能力)
也就是说不仅要指定泛型是什么类型,还要指定这个类型具有什么能力,否则函数不知道你能做什么
泛型函数
rust
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
let mut largest = list[0];
for &item in list.iter() {
if item > largest {
largest = item;
}
}
largest
}这里的 T 指的就是函数参数的类型,可以是任意类型,但必须实现 PartialOrd(用于比较)和 Copy(用于复制)两个 trait.
泛型结构体
rust
struct Point<T> {
x: T,
y: T,
}结构体中的字段 x 和 y 必须是同一种类型 T.如果需要不同类型,可以使用多个泛型参数:
rust
struct Point<T, U> {
x: T,
y: U,
}为泛型结构体实现方法
rust
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}
// 任意 Point<T> 实例都实现 x() 方法
// 注意必须在 impl 后面声明 T,这样就可以在 Point<T> 上实现的方法中使用 T 了
// 通过在 impl 之后声明泛型 T,Rust 就知道 Point 的尖括号中的类型是泛型而不是具体类型
// 如果写成 impl Point { },编译器会认为你要为具体的 Point 类型实现方法为泛型添加 Trait 约束
rust
impl<T: std::fmt::Display> Point<T> {
fn print(&self) {
println!("{}", self.x);
}
}
// 不仅指定了泛型 T,还指定了 T 必须实现 Display trait
// 这样 Point<T> 才拥有 print() 方法或者使用 where 子句:
rust
impl<T> Point<T>
where
T: std::fmt::Display,
{
fn print(&self) {
println!("{}", self.x);
}
}为特定类型实现方法
rust
impl Point<f32> {
fn distance_from_origin(&self) -> f32 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}
// 这段代码意味着只有 Point<f32> 类型的实例才有 distance_from_origin() 方法
// 其他 T 不是 f32 类型的 Point<T> 实例则没有此方法完整示例
rust
fn main() {
let p = Point { x: 5, y: 10 };
dbg!(p.x()); // 使用泛型方法
p.print(); // 使用受 Trait 约束的方法
// dbg!(p.distance_from_origin()); // 编译错误: Point<i32> 没有此方法
let f = Point { x: 5.5, y: 10.1 };
dbg!(f.x()); // 使用泛型方法
f.print(); // 使用受 Trait 约束的方法
dbg!(f.distance_from_origin()); // ✅ 可以使用 Point<f32> 独家方法
}泛型的单态化
Rust 编译器会在编译期根据使用的具体类型为每个泛型生成专门的代码,这个过程叫单态化(monomorphization).虽然代码会略微增大,但运行性能与手写特定类型的代码相同.