Trait

Trait 类似于其他语言中的接口(interface),定义共享行为。

定义 Trait

pub trait Summary {
    fn summarize(&self) -> String;
}

pub struct NewsArticle {
    pub headline: String,
    pub content: String,
}

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

fn main() {
    let article = NewsArticle {
        headline: String::from("重大新闻"),
        content: String::from("内容详情"),
    };

    println!("{}", article.summarize());
}

默认实现

pub trait Summary {
    fn summarize(&self) -> String {
        String::from("(阅读更多...)")  // 默认实现
    }
}

impl Summary for NewsArticle {}  // 使用默认实现

Trait 作为参数

// impl Trait 语法
pub fn notify(item: &impl Summary) {
    println!("快讯!{}", item.summarize());
}

// Trait bound 语法(更灵活)
pub fn notify<T: Summary>(item: &T) {
    println!("快讯!{}", item.summarize());
}

// 多个 trait 约束
pub fn notify<T: Summary + Display>(item: &T) {
    // ...
}

// where 子句
pub fn notify<T>(item: &T)
where
    T: Summary + Display,
{
    // ...
}

返回实现 Trait 的类型

fn returns_summarizable() -> impl Summary {
    NewsArticle {
        headline: String::from("标题"),
        content: String::from("内容"),
    }
}

Trait 关系可视化

Trait 继承关系
实现(implements)
继承(trait bounds)

孤儿规则

只有当 trait 或类型至少有一个在本地 crate 时,才能为类型实现 trait:

// ✅ 可以:为本地类型实现标准库 trait
impl Display for MyStruct { }

// ✅ 可以:为标准库类型实现本地 trait
impl MyTrait for Vec<i32> { }

// ❌ 不可以:为外部类型实现外部 trait
impl Display for Vec<i32> { }  // 编译错误

标准库常用 Trait

Clone 和 Copy

#[derive(Clone, Copy)]
struct Point {
    x: i32,
    y: i32,
}

Debug 和 Display

#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

use std::fmt;

impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

PartialEq 和 Eq

#[derive(PartialEq, Eq)]
struct Point {
    x: i32,
    y: i32,
}

Trait 对象

pub trait Draw {
    fn draw(&self);
}

pub struct Screen {
    pub components: Vec<Box<dyn Draw>>,  // Trait 对象
}

impl Screen {
    pub fn run(&self) {
        for component in self.components.iter() {
            component.draw();
        }
    }
}

静态分发 vs 动态分发

  • impl Trait:静态分发,编译时确定,零开销
  • dyn Trait:动态分发,运行时确定,有虚表开销

关联类型

pub trait Iterator {
    type Item;  // 关联类型

    fn next(&mut self) -> Option<Self::Item>;
}

Trait 继承

trait OutlinePrint: fmt::Display {
    fn outline_print(&self) {
        println!("* {} *", self);  // 可以使用 Display 的 to_string
    }
}

小结

  • ✅ Trait 定义共享行为
  • ✅ 可以有默认实现
  • ✅ 使用 impl Trait 或 Trait bound 作为参数
  • dyn Trait 实现动态分发
  • ✅ 孤儿规则防止冲突
  • ✅ 标准库提供了许多常用 Trait