阶段五:泛型与 Trait

100 阅读2分钟

核心知识点

  1. 泛型(Generics)

    • 编写可用于多种类型的代码(函数、结构体、枚举)
    • 示例:Option<T>, Result<T, E> 本身就是泛型类型
  2. Trait

    • 定义共享行为(类似接口)
    • 通过 impl Trait for Type 实现行为
    • 常见 Trait:Debug, Clone, Display, Iterator
  3. Trait Bound

    • 限制泛型类型必须实现某些 Trait
    • 语法:fn f<T: TraitA + TraitB>(x: T) { ... }
  4. 生命周期 + 泛型组合使用

    • 标注泛型数据的生命周期

学习步骤

1. 泛型函数与结构体

// 泛型函数:返回两个值中较大的那个
fn largest<T: PartialOrd>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

// 泛型结构体
struct Point<T> {
    x: T,
    y: T,
}

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

2. 定义并实现 Trait

// 定义 Trait
pub trait Summary {
    fn summarize(&self) -> String;
}

// 为结构体实现 Trait
struct NewsArticle {
    headline: String,
    content: String,
}

impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        format!("标题: {}", self.headline)
    }
}

3. Trait Bound 的使用

// 使用 Trait Bound 约束泛型
fn notify<T: Summary>(item: &T) {
    println!("新通知: {}", item.summarize());
}

// 简化写法:`impl Trait` 语法
fn get_summarizable() -> impl Summary {
    NewsArticle { /* ... */ }
}

练习题

题目1:泛型最大值函数

// 实现函数 largest,返回切片中的最大值
fn largest<T: PartialOrd>(list: &[T]) -> &T {
    let mut largest = &list[0];
    for item in list {
        if item > largest {
            largest = item;
        }
    }
    largest
}

fn main() {
    let numbers = vec![34, 50, 25, 100, 65];
    println!("最大数字: {}", largest(&numbers));

    let chars = vec!['y', 'm', 'a', 'q'];
    println!("最大字符: {}", largest(&chars));
}

题目2:为 Point 实现 Display

use std::fmt;

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

// 为所有 Point<T> 实现 Display
impl<T: fmt::Display> fmt::Display for Point<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

fn main() {
    let p = Point { x: 5, y: 10 };
    println!("坐标: {}", p); // 输出 (5, 10)
}

题目3:自定义 Drawable Trait

// 定义 Trait
trait Drawable {
    fn draw(&self);
}

// 实现结构体
struct Circle { radius: f64 }
struct Square { side: f64 }

impl Drawable for Circle {
    fn draw(&self) {
        println!("绘制圆形,半径: {}", self.radius);
    }
}

impl Drawable for Square {
    fn draw(&self) {
        println!("绘制正方形,边长: {}", self.side);
    }
}

// 接受实现 Drawable 的泛型函数
fn render<T: Drawable>(item: &T) {
    item.draw();
}

fn main() {
    let circle = Circle { radius: 3.0 };
    let square = Square { side: 2.5 };

    render(&circle); // 输出:绘制圆形,半径: 3
    render(&square); // 输出:绘制正方形,边长: 2.5
}

关键技巧

  1. derive 自动实现 Trait

    • 使用 #[derive(Debug, Clone)] 让编译器自动生成常见 Trait 的实现
    #[derive(Debug, PartialEq)]
    struct Data {
        value: i32,
    }
    
  2. Trait 的默认实现

    • 在 Trait 定义中提供默认方法:
    trait Summary {
        fn summarize(&self) -> String {
            String::from("(阅读更多...)")
        }
    }
    
  3. 使用 where 简化复杂 Trait Bound

    fn some_func<T, U>(t: &T, u: &U) -> i32
    where
        T: Display + Clone,
        U: Debug + PartialEq,
    {
        // ...
    }
    

常见错误

错误:T doesn't implement a trait

fn print_debug<T>(value: T) {
    println!("{:?}", value); // 错误!T 未实现 Debug
}
  • 修复:添加 Trait Bound
    fn print_debug<T: Debug>(value: T) { ... }
    

下一步任务

  1. 完成练习题,尝试为你的自定义结构体实现 Iterator Trait
  2. 阅读《Rust 程序设计语言》第10章
  3. 探索标准库中的常见 Trait(如 From, Into, Drop