Skip to content

泛型

  • 类似函数的参数,这是一种类型参数
  • 与 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,
}

结构体中的字段 xy 必须是同一种类型 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).虽然代码会略微增大,但运行性能与手写特定类型的代码相同.

基于 MIT 协议发布