Skip to content

泛型类型

> 掌握泛型结构体和枚举的定义方法,学习泛型实现和特定类型实现的技巧。

泛型结构体

定义泛型结构体

rust
// 单个泛型参数
#[derive(Debug)]
struct Point<T> {
    x: T,
    y: T,
}

fn main() {
    // 整数坐标
    let integer = Point { x: 5, y: 10 };
    println!("{:?}", integer);

    // 浮点坐标
    let float = Point { x: 1.0, y: 4.0 };
    println!("{:?}", float);

    // 类型推断
    let p = Point { x: 5, y: 10 };
    println!("{:?}", p);

    // 显式标注
    let p: Point<f64> = Point { x: 1.0, y: 2.0 };
}
▶ Run

多个泛型参数

rust
// 多个泛型参数,字段可以是不同类型
#[derive(Debug)]
struct Point<T, U> {
    x: T,
    y: U,
}

fn main() {
    // 相同类型
    let p1 = Point { x: 5, y: 10 };         // Point<i32, i32>
    let p2 = Point { x: 1.0, y: 2.0 };      // Point<f64, f64>

    // 不同类型
    let p3 = Point { x: 5, y: 10.0 };       // Point<i32, f64>
    let p4 = Point { x: "hello", y: 'A' };  // Point<&str, char>
    let p5 = Point { x: vec![1, 2], y: "test" }; // Point<Vec<i32>, &str>

    println!("p3: {:?}", p3);
    println!("p4: {:?}", p4);
    println!("p5: {:?}", p5);
}
▶ Run

泛型枚举

rust
// 标准库中的 Option 和 Result 都是泛型枚举
enum Option<T> {
    Some(T),
    None,
}

enum Result<T, E> {
    Ok(T),
    Err(E),
}

// 自定义泛型枚举
#[derive(Debug)]
enum Message<T> {
    Quit,                      // 无数据
    Move { x: T, y: T },      // 命名字段
    Write(T),                  // 单个值
    ChangeColor(T, T, T),     // 多个值
}

fn main() {
    // Option 示例
    let some_number: Option<i32> = Some(42);
    let none_number: Option<String> = None;

    // Result 示例
    let success: Result<i32, &str> = Ok(42);
    let failure: Result<i32, &str> = Err("错误");

    // Message 示例
    let m1: Message<i32> = Message::Quit;
    let m2: Message<f64> = Message::Move { x: 1.0, y: 2.0 };
    let m3: Message<String> = Message::Write(String::from("hello"));

    println!("m2: {:?}", m2);
    println!("m3: {:?}", m3);
}
▶ Run

泛型结构体的内存布局

Point<i32> 和 Point<f64> 在内存中是不同的:

Point<i32>:
┌─────┬─────┐
│  x  │  y  │
│ i32 │ i32 │  = 8 字节
│ 4B  │ 4B  │
└─────┴─────┘

Point<f64>:
┌─────┬─────┐
│  x  │  y  │
│f64  │f64  │  = 16 字节
│ 8B  │ 8B  │
└─────┴─────┘

Point<i32, f64>:
┌─────┬─────┐
│  x  │  y  │
│i32  │f64  │  = 16 字节(考虑对齐)
│ 4B  │ 8B  │
└─────┴─────┘

关键点:
• 每个具体类型组合都会生成独立的结构体
• 没有运行时类型信息(RTTI)开销
• 内存布局与手写专用代码完全相同

泛型实现

impl 泛型参数

rust
#[derive(Debug)]
struct Point<T> {
    x: T,
    y: T,
}

// 为所有 T 实现方法
impl<T> Point<T> {
    // 访问器
    fn x(&self) -> &T {
        &self.x
    }

    fn y(&self) -> &T {
        &self.y
    }

    // 获取两个坐标的引用
    fn coordinates(&self) -> (&T, &T) {
        (&self.x, &self.y)
    }
}

// 需要特定 trait 约束的方法
impl<T: PartialOrd> Point<T> {
    // 判断 x 是否大于 y
    fn x_greater_than_y(&self) -> bool {
        self.x > self.y
    }
}

// Clone 约束
impl<T: Clone> Point<T> {
    fn duplicate(&self) -> Self {
        Point {
            x: self.x.clone(),
            y: self.y.clone(),
        }
    }
}

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

    println!("x = {:?}", p.x());
    println!("y = {:?}", p.y());
    println!("coordinates = {:?}", p.coordinates());
    println!("duplicated = {:?}", p.duplicate());
}
▶ Run

特定类型的实现

rust
struct Point<T> {
    x: T,
    y: T,
}

// 为特定类型实现额外方法
impl Point<f32> {
    fn distance_from_origin(&self) -> f32 {
        (self.x.powi(2) + self.y.powi(2)).sqrt()
    }

    fn rotate_90_degrees(&mut self) {
        let new_x = -self.y;
        let new_y = self.x;
        self.x = new_x;
        self.y = new_y;
    }
}

impl Point<i32> {
    fn manhattan_distance(&self) -> i32 {
        self.x.abs() + self.y.abs()
    }
}

fn main() {
    let p1 = Point { x: 3.0, y: 4.0 };
    println!("欧几里得距离:{}", p1.distance_from_origin());  // 5.0

    let p2 = Point { x: 3, y: 4 };
    println!("曼哈顿距离:{}", p2.manhattan_distance());  // 7

    // p2.manhattan_distance() 只有 Point<i32> 才有
    // p1.distance_from_origin() 只有 Point<f32> 才有
}
▶ Run

多类型泛型的复杂实现

rust
struct Point<X, Y> {
    x: X,
    y: Y,
}

// 为所有 X, Y 实现
impl<X, Y> Point<X, Y> {
    fn x(&self) -> &X {
        &self.x
    }

    fn y(&self) -> &Y {
        &self.y
    }
}

// mixup 方法:混合两个不同 Point 的坐标
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,
        }
    }
}

// Clone 约束
impl<X: Clone, Y: Clone> Point<X, Y> {
    fn clone_coords(&self) -> (X, Y) {
        (self.x.clone(), self.y.clone())
    }
}

fn main() {
    let p1 = Point { x: 5, y: 10.4 };   // Point<i32, f64>
    let p2 = Point { x: "Hello", y: 'c' };  // Point<&str, char>

    let p3 = p1.mixup(p2);  // Point<i32, char>

    println!("p3.x = {:?}, p3.y = {}", p3.x(), p3.y());

    // p1 已移动,但可以使用 clone_coords
    // println!("{:?}", p1.clone_coords());
}
▶ Run

带有 trait 约束的实现

rust
use std::fmt::Display;

struct Pair<T> {
    x: T,
    y: T,
}

impl<T> Pair<T> {
    fn new(x: T, y: T) -> Self {
        Self { x, y }
    }
}

// 只有 T 实现 Display + PartialOrd 时才能调用
impl<T: Display + PartialOrd> Pair<T> {
    fn cmp_display(&self) {
        if self.x >= self.y {
            println!("较大的值是:{}", self.x);
        } else {
            println!("较大的值是:{}", self.y);
        }
    }
}

// 只有 T 实现 Display 时才能打印
impl<T: Display> Pair<T> {
    fn print_pair(&self) {
        println!("({}, {})", self.x, self.y);
    }
}

fn main() {
    let p1 = Pair::new(5, 10);
    p1.cmp_display();      // 较大的值是:10
    p1.print_pair();       // (5, 10)

    let p2 = Pair::new(3.14, 2.71);
    p2.cmp_display();      // 较大的值是:3.14
}




---

## 小结

- 泛型结构体使用 `struct Name<T>` 定义,可以有多个泛型参数
- `impl<T> Name<T>` 为所有 T 实现方法,`impl Name<f32>` 为特定类型实现
- 泛型枚举如 `Option<T>` 和 `Result<T, E>` 是标准库核心类型
- 不同具体类型组合会在编译时生成不同的结构体
-trait 约束的方法只为满足条件的类型提供

## 练习题

详见:[练习题](../../exercises/15-generics)
▶ Run