Files
rust/Trait/readme.md
2025-10-05 23:51:24 +08:00

6.8 KiB
Raw Blame History

非常好 👍 trait 是 Rust 中非常核心、非常强大的概念之一,几乎等价于 C++ 的「接口interface」或「抽象基类abstract base class 但 Rust 的 trait 更安全、更灵活、还能与泛型深度结合。

下面我们来从直觉 → 语法 → 实战 → 泛型结合 → 高级技巧系统地讲清楚 Rust 的 trait 怎么用。


🧩 一、Trait 是什么?

一句话解释:

Trait 定义了一组类型必须实现的“能力”或“行为”

比如“能打印”、“能比较大小”、“能移动”等行为,都可以用 trait 定义。


🧠 二、最简单的 trait 示例

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

上面定义了一个 Summary 特征trait它表示“这个类型能生成一个概要字符串”。

任何想拥有这个功能的类型,都要实现它。


💡 三、为结构体实现 trait

struct NewsArticle {
    title: String,
    author: String,
    content: String,
}

impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        format!("{} by {}", self.title, self.author)
    }
}

现在,NewsArticle 类型就有了 .summarize() 方法:

fn main() {
    let article = NewsArticle {
        title: String::from("Rust trait 学习指南"),
        author: String::from("Evan"),
        content: String::from("内容..."),
    };

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

输出:

Rust trait 学习指南 by Evan

🔧 四、Trait = 行为接口(类比 C++

概念 Rust C++ 类似
定义接口 trait Summary { ... } class Summary { virtual ... = 0; }
实现接口 impl Summary for NewsArticle class NewsArticle : public Summary { ... }
调用接口 item.summarize() item.summarize()
多态传参 fn notify(item: &impl Summary) void notify(const Summary& item)

⚙️ 五、trait 作为函数参数(多态)

fn notify(item: &impl Summary) {
    println!("Breaking news! {}", item.summarize());
}

这个函数可以接受任何实现了 Summary 的类型

let article = NewsArticle {
    title: String::from("Rust 1.80 发布!"),
    author: String::from("官方"),
    content: String::from("..."),
};

notify(&article);

🔄 六、与泛型结合的写法

等价的更通用写法是:

fn notify<T: Summary>(item: &T) {
    println!("Breaking news! {}", item.summarize());
}

这两种写法效果一致:

  • fn foo(x: &impl Trait):语法糖
  • fn foo<T: Trait>(x: &T):完整泛型写法,可组合多个 trait

🧩 七、多个 trait 约束

如果希望一个类型实现多个 trait 才能传入:

fn show<T: Summary + Clone>(item: &T) {
    println!("{}", item.summarize());
}

或者更清晰的写法:

fn show<T>(item: &T)
where
    T: Summary + Clone,
{
    println!("{}", item.summarize());
}

🔁 八、Trait 默认实现

trait 还可以提供默认方法实现

trait Summary {
    fn summarize(&self) -> String {
        String::from("(Read more...)")
    }
}

实现时可以选择覆盖它:

impl Summary for NewsArticle {
    // 也可以不写 summarize(),直接用默认实现
}

🧩 九、返回实现 trait 的类型impl Trait 返回)

函数也可以返回实现某个 trait 的类型

fn make_article() -> impl Summary {
    NewsArticle {
        title: String::from("Hello"),
        author: String::from("Rust"),
        content: String::from("..."),
    }
}

这里的 impl Summary 意思是“返回一个实现了 Summary 的对象”, 但不能同时返回多种不同类型(必须一致)。


💥 十、trait 对象(动态分发)

如果你希望“一个变量”能存放多种类型但都有共同 trait,用 Box<dyn Trait>

fn main() {
    let article = NewsArticle {
        title: String::from("Rust"),
        author: String::from("Evan"),
        content: String::from("..."),
    };

    let tweet = Tweet {
        username: String::from("rustacean"),
        content: String::from("trait 太强了"),
    };

    let items: Vec<Box<dyn Summary>> = vec![
        Box::new(article),
        Box::new(tweet),
    ];

    for i in items {
        println!("{}", i.summarize());
    }
}

这就类似于 C++ 的虚函数表vtable动态多态。


🧩 十一、完整例子trait、泛型、多态一起

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

struct NewsArticle {
    title: String,
    author: String,
}

struct Tweet {
    username: String,
    content: String,
}

impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        format!("{} by {}", self.title, self.author)
    }
}

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

fn notify<T: Summary>(item: &T) {
    println!("Breaking news! {}", item.summarize());
}

fn main() {
    let tweet = Tweet {
        username: String::from("EvanZ"),
        content: String::from("Rust trait 学到了!"),
    };
    let article = NewsArticle {
        title: String::from("学习 Rust 的一天"),
        author: String::from("Evan"),
    };

    notify(&tweet);
    notify(&article);
}

输出:

Breaking news! @EvanZ: Rust trait 学到了!
Breaking news! 学习 Rust 的一天 by Evan

十二、总结表

功能 语法 含义
定义 trait trait TraitName { fn func(&self); } 定义行为接口
实现 trait impl TraitName for Type { ... } 给类型实现行为
参数约束 fn f<T: Trait>(t: &T)fn f(t: &impl Trait) 仅接受实现了 Trait 的类型
多 trait T: TraitA + TraitB 同时要求多个行为
返回 trait -> impl Trait 返回实现了该行为的类型
动态多态 Box<dyn Trait> 在运行时存放不同实现
默认实现 fn func(&self) { ... } 允许被覆盖或继承默认功能

是否希望我接着讲讲 trait 与泛型的底层机制(即静态分发 vs 动态分发的区别),包括它们的性能差异与编译原理?(这部分对理解 Rust trait 的“真功夫”非常有帮助)