# 第六章 Trait 与泛型：Rust 的多态

> *"Program to an interface, not an implementation." — Gang of Four*

在 C++ 中我们用虚函数和模板实现多态，在 Java 中我们用 interface 和泛型。Rust 的答案是 **Trait + 泛型**——它既能做到零成本的静态分发，也支持灵活的动态分发，而且在编译期就能捕获大多数类型错误。

本章将带你全面掌握 Rust 的多态机制，并与你熟悉的 C++/Java 概念逐一对照。

```mermaid
mindmap
  root((Trait 与泛型))
    Trait
      共享行为
      默认实现
      trait bound
    泛型
      类型参数
      where 约束
      单态化
    分发
      静态分发
      dyn Trait
      对象安全
    对比
      Java interface
      C++ template
      Go interface
```

---

## 6.1 什么是 Trait？

Trait 是 Rust 中定义**共享行为**的方式。你可以把它理解为：

- Java 的 `interface`（但可以有默认实现）
- C++ 的纯虚基类 + Concepts（C++20）
- Go 的 `interface`（但是显式实现，非鸭子类型）

### 6.1.1 定义一个 Trait

```rust
/// 任何可以被摘要展示的类型
trait Summary {
    fn summarize(&self) -> String;

    // 默认实现——实现者可以选择覆盖
    fn preview(&self) -> String {
        format!("{}...", &self.summarize()[..20.min(self.summarize().len())])
    }
}
```

### 6.1.2 为类型实现 Trait

```rust
struct Article {
    title: String,
    author: String,
    content: String,
}

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

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

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

使用：

```rust
fn main() {
    let article = Article {
        title: String::from("Rust 2024"),
        author: String::from("Walter"),
        content: String::from("Rust is awesome..."),
    };
    let tweet = Tweet {
        username: String::from("rustlang"),
        text: String::from("Rust 1.80 is out!"),
    };

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

### 6.1.3 方法接收者：`&self`、`&mut self` 与 `self`

Trait 方法的第一个参数经常写成 `&self`、`&mut self` 或 `self`。它们不是三种不同的对象模型，而是三种**所有权选择**：

| 接收者 | 含义 | 适合场景 |
|--------|------|----------|
| `&self` | 不可变借用当前对象 | 只读查询、格式化、计算派生值 |
| `&mut self` | 可变借用当前对象 | 修改内部状态，但不消费对象 |
| `self` | 获取当前对象所有权 | 消费对象、转换对象、链式 builder 结束 |

```rust
trait Cache {
    fn name(&self) -> &str;
    fn put(&mut self, key: String, value: String);
    fn into_entries(self) -> Vec<(String, String)>;
}
```

对调用者来说，这三种写法直接决定对象还能不能继续用：

```rust
use std::collections::HashMap;

struct MemoryCache {
    name: String,
    entries: HashMap<String, String>,
}

impl Cache for MemoryCache {
    fn name(&self) -> &str {
        &self.name
    }

    fn put(&mut self, key: String, value: String) {
        self.entries.insert(key, value);
    }

    fn into_entries(self) -> Vec<(String, String)> {
        self.entries.into_iter().collect()
    }
}

fn main() {
    let mut cache = MemoryCache {
        name: "local".into(),
        entries: HashMap::new(),
    };

    println!("{}", cache.name());               // &self：cache 仍可继续用
    cache.put("theme".into(), "dark".into());   // &mut self：修改 cache
    let entries = cache.into_entries();         // self：cache 被消费

    // println!("{}", cache.name());            // ❌ cache 已经移动
    println!("{:?}", entries);
}
```

经验法则：默认先选 `&self`；需要改状态时选 `&mut self`；方法的语义是“把这个对象变成另一个东西”时才选 `self`。

### 6.1.4 三语对比：定义与实现

| 特性 | Rust | C++ | Java |
|------|------|-----|------|
| 定义接口 | `trait Summary { ... }` | `class Summary { virtual ... = 0; }` | `interface Summary { ... }` |
| 实现接口 | `impl Summary for Article { ... }` | `class Article : public Summary { ... }` | `class Article implements Summary { ... }` |
| 默认实现 | ✅ trait 中直接写 | ✅ 虚函数提供默认实现 | ✅ `default` 方法（Java 8+） |
| 为外部类型实现 | ✅（孤儿规则限制下） | ❌ 需要继承或 adapter | ❌ 不可能 |
| 多重实现 | ✅ 一个类型可 impl 多个 trait | ✅ 多重继承（菱形问题） | ✅ 多个 interface |

---

## 6.2 Trait Bound 与泛型

### 6.2.1 泛型函数

```rust
// 接受任何实现了 Summary 的类型
fn notify(item: &impl Summary) {
    println!("Breaking: {}", item.summarize());
}
```

这是语法糖，完整写法是 **Trait Bound**：

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

### 6.2.2 多个 Trait Bound

```rust
use std::fmt::Display;

fn notify_and_display<T: Summary + Display>(item: &T) {
    println!("{}", item.summarize());
    println!("{}", item);  // 要求 T 同时实现 Display
}
```

当约束变多时，使用 `where` 子句更清晰：

```rust
fn complex_function<T, U>(t: &T, u: &U) -> String
where
    T: Summary + Clone,
    U: Display + Debug,
{
    format!("{} - {:?}", t.summarize(), u)
}
```

### 6.2.3 三语对比：泛型约束

| 特性 | Rust | C++ | Java |
|------|------|-----|------|
| 泛型语法 | `fn foo<T>(x: T)` | `template<typename T> void foo(T x)` | `<T> void foo(T x)` |
| 约束 | `T: Trait` | `concept` (C++20) 或 SFINAE | `T extends Interface` |
| 编译时检查 | ✅ 严格 | ✅ (concept) / ❌ (模板错误信息差) | ✅ 类型擦除后有限检查 |
| 单态化 | ✅ 每个具体类型生成一份代码 | ✅ 模板实例化 | ❌ 类型擦除，运行时一份代码 |

```mermaid
graph LR
    A[泛型函数 notify&lt;T&gt;] -->|T = Article| B[notify_Article 单态化版本]
    A -->|T = Tweet| C[notify_Tweet 单态化版本]
    style A fill:#f9f,stroke:#333
    style B fill:#bbf,stroke:#333
    style C fill:#bbf,stroke:#333
```

> **单态化（Monomorphization）**：Rust 编译器为每个具体类型生成专用代码，因此泛型调用的性能等同于手写具体类型的代码——这就是"零成本抽象"。

---

## 6.3 静态分发 vs 动态分发

这是 Rust 多态最核心的设计决策。

### 6.3.1 静态分发（impl Trait / 泛型）

```rust
fn print_summary(item: &impl Summary) {
    println!("{}", item.summarize());
}
```

- 编译时确定具体类型
- 生成专用代码（单态化）
- **零运行时开销**
- 代价：二进制体积可能增大

### 6.3.2 动态分发（dyn Trait）

```rust
fn print_summary_dyn(item: &dyn Summary) {
    println!("{}", item.summarize());
}
```

- 通过 **虚表（vtable）** 在运行时查找方法
- 只生成一份代码
- 有一次指针间接寻址的开销
- 适合需要**异构集合**的场景

```rust
fn main() {
    let article = Article {
        title: String::from("Rust Traits"),
        author: String::from("Walter"),
        content: String::from("..."),
    };
    let tweet = Tweet {
        username: String::from("rustlang"),
        text: String::from("Hello!"),
    };

    // 异构集合：不同类型放在同一个 Vec 中
    let items: Vec<Box<dyn Summary>> = vec![
        Box::new(article),
        Box::new(tweet),
    ];

    for item in &items {
        println!("{}", item.summarize());
    }
}
```

### 6.3.3 dyn Trait 的内存布局

```mermaid
graph TD
    subgraph "Box&lt;dyn Summary&gt; = 胖指针"
        P1[数据指针] --> D[Article 实例数据]
        P2[vtable 指针] --> V[vtable]
    end
    subgraph "vtable"
        V --> M1["summarize() 函数指针"]
        V --> M2["preview() 函数指针"]
        V --> M3["drop() 函数指针"]
        V --> M4["size / align"]
    end
    style P1 fill:#fbb,stroke:#333
    style P2 fill:#bfb,stroke:#333
```

### 6.3.4 三语对比：分发机制

| 分发方式 | Rust | C++ | Java |
|----------|------|-----|------|
| 静态分发 | `impl Trait` / 泛型 | 模板 | 不支持（泛型是类型擦除） |
| 动态分发 | `dyn Trait` | `virtual` 函数 | 接口方法调用（默认动态） |
| 选择权 | **程序员显式选择** | 是否加 `virtual` | 无选择（总是动态） |
| 性能 | 静态 ≈ 零开销；动态 ≈ 一次间接调用 | 同 Rust | 总是有虚调用开销 |

---

## 6.4 常用标准库 Trait

Rust 标准库定义了大量 trait，掌握它们是写出地道 Rust 代码的关键。

### 6.4.1 Display 与 Debug

```rust
use std::fmt;

struct Point {
    x: f64,
    y: f64,
}

// Display：面向用户的格式化
impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

// Debug：面向开发者的格式化（通常用 derive 自动生成）
#[derive(Debug)]
struct Rect {
    top_left: Point,
    bottom_right: Point,
}
```

### 6.4.2 Clone 与 Copy

```rust
// Clone：显式深拷贝
#[derive(Clone)]
struct Config {
    name: String,
    values: Vec<i32>,
}

// Copy：隐式按位复制（仅适用于栈上的简单类型）
#[derive(Copy, Clone)]
struct Color {
    r: u8,
    g: u8,
    b: u8,
}
```

**规则**：实现 `Copy` 的类型必须同时实现 `Clone`；包含堆数据（如 `String`、`Vec`）的类型不能实现 `Copy`。

### 6.4.3 From 与 Into

```rust
struct Celsius(f64);
struct Fahrenheit(f64);

impl From<Celsius> for Fahrenheit {
    fn from(c: Celsius) -> Self {
        Fahrenheit(c.0 * 9.0 / 5.0 + 32.0)
    }
}

fn main() {
    let boiling = Celsius(100.0);
    let f: Fahrenheit = boiling.into();  // 自动获得 Into
    println!("Water boils at {}°F", f.0);
}
```

### 6.4.4 Iterator

```rust
struct Counter {
    count: u32,
    max: u32,
}

impl Counter {
    fn new(max: u32) -> Self {
        Counter { count: 0, max }
    }
}

impl Iterator for Counter {
    type Item = u32;  // 关联类型

    fn next(&mut self) -> Option<Self::Item> {
        if self.count < self.max {
            self.count += 1;
            Some(self.count)
        } else {
            None
        }
    }
}

fn main() {
    let sum: u32 = Counter::new(5)
        .filter(|x| x % 2 == 0)
        .sum();
    println!("Sum of even numbers: {}", sum); // 2 + 4 = 6
}
```

### 6.4.5 常用 Trait 速查表

| Trait | 用途 | 常见 derive |
|-------|------|-------------|
| `Debug` | 调试输出 `{:?}` | ✅ `#[derive(Debug)]` |
| `Display` | 用户友好输出 `{}` | ❌ 需手动实现 |
| `Clone` | 显式深拷贝 `.clone()` | ✅ `#[derive(Clone)]` |
| `Copy` | 隐式按位复制 | ✅ `#[derive(Copy)]` |
| `PartialEq` / `Eq` | 相等比较 `==` | ✅ `#[derive(PartialEq, Eq)]` |
| `PartialOrd` / `Ord` | 排序比较 `<` `>` | ✅ `#[derive(PartialOrd, Ord)]` |
| `Hash` | 哈希（用于 HashMap 的 key） | ✅ `#[derive(Hash)]` |
| `Default` | 默认值 | ✅ `#[derive(Default)]` |
| `From` / `Into` | 类型转换 | ❌ 需手动实现 |
| `Iterator` | 迭代器 | ❌ 需手动实现 |
| `Drop` | 析构逻辑（类似 C++ 析构函数） | ❌ 需手动实现 |

---

## 6.5 关联类型 vs 泛型参数

### 6.5.1 关联类型

```rust
trait Graph {
    type Node;      // 关联类型
    type Edge;

    fn edges(&self, node: &Self::Node) -> Vec<Self::Edge>;
}
```

### 6.5.2 泛型参数

```rust
trait Converter<From, To> {
    fn convert(&self, input: From) -> To;
}
```

### 6.5.3 何时用哪个？

| 场景 | 选择 | 理由 |
|------|------|------|
| 一个类型只有一种实现 | 关联类型 | `Iterator` 的 `Item` 对每个类型只有一种 |
| 一个类型可能有多种实现 | 泛型参数 | `From<T>` 可以从多种类型转换 |

```mermaid
flowchart TD
    Q["一个类型对此 trait<br>是否有多种实现？"]
    Q -->|否，只有一种| A["用关联类型<br>type Item = ..."]
    Q -->|是，可能多种| B["用泛型参数<br>Trait&lt;T&gt;"]
    A --> E1["例：Iterator"]
    B --> E2["例：From&lt;T&gt;"]
    style Q fill:#ffe,stroke:#333
    style A fill:#bfb,stroke:#333
    style B fill:#bbf,stroke:#333
```

---

## 6.6 Trait 对象的限制：对象安全

并非所有 trait 都能用作 `dyn Trait`。能用作 trait 对象的 trait 必须是**对象安全的（object safe）**。

### 规则

一个 trait 是对象安全的，当且仅当：

1. **所有方法的接收者是 `&self`、`&mut self` 或 `self: Box<Self>`**
2. **方法没有泛型参数**
3. **方法的返回类型不是 `Self`**（`Clone` 的 `fn clone(&self) -> Self` 就不行）

```rust
// ✅ 对象安全
trait Drawable {
    fn draw(&self);
    fn area(&self) -> f64;
}

// ❌ 不是对象安全的——返回 Self
trait Cloneable {
    fn clone_self(&self) -> Self;
}

// ❌ 不是对象安全的——方法有泛型参数
trait Serializer {
    fn serialize<W: std::io::Write>(&self, writer: &mut W);
}
```

### 解决方案

如果你需要在 trait 对象中使用类似 `Clone` 的功能：

```rust
trait CloneBox {
    fn clone_box(&self) -> Box<dyn CloneBox>;
}

impl<T: Clone + 'static> CloneBox for T {
    fn clone_box(&self) -> Box<dyn CloneBox> {
        Box::new(self.clone())
    }
}
```

---

## 6.7 实战：为 Hive 项目设计插件 Trait

让我们用本章知识为贯穿全书的 Hive 项目设计一个插件系统的 trait：

```rust
use std::any::Any;

/// 插件元数据
#[derive(Debug, Clone)]
struct PluginMeta {
    name: String,
    version: String,
    description: String,
}

/// Hive 插件 trait
trait Plugin: Any + Send + Sync {
    /// 返回插件元数据
    fn meta(&self) -> PluginMeta;

    /// 插件初始化
    fn on_load(&mut self) -> Result<(), Box<dyn std::error::Error>>;

    /// 插件卸载
    fn on_unload(&mut self) -> Result<(), Box<dyn std::error::Error>>;

    /// 处理事件
    fn handle_event(&self, event: &str, payload: &str) -> Option<String>;
}

/// 一个示例插件：Markdown 预览
struct MarkdownPlugin {
    meta: PluginMeta,
    loaded: bool,
}

impl MarkdownPlugin {
    fn new() -> Self {
        Self {
            meta: PluginMeta {
                name: "markdown-preview".into(),
                version: "0.1.0".into(),
                description: "Render Markdown to HTML".into(),
            },
            loaded: false,
        }
    }
}

impl Plugin for MarkdownPlugin {
    fn meta(&self) -> PluginMeta {
        self.meta.clone()
    }

    fn on_load(&mut self) -> Result<(), Box<dyn std::error::Error>> {
        println!("[{}] Plugin loaded", self.meta.name);
        self.loaded = true;
        Ok(())
    }

    fn on_unload(&mut self) -> Result<(), Box<dyn std::error::Error>> {
        println!("[{}] Plugin unloaded", self.meta.name);
        self.loaded = false;
        Ok(())
    }

    fn handle_event(&self, event: &str, payload: &str) -> Option<String> {
        match event {
            "render" => {
                // 简化的 Markdown → HTML 转换
                let html = payload
                    .lines()
                    .map(|line| {
                        if line.starts_with("# ") {
                            format!("<h1>{}</h1>", &line[2..])
                        } else if line.starts_with("## ") {
                            format!("<h2>{}</h2>", &line[3..])
                        } else {
                            format!("<p>{}</p>", line)
                        }
                    })
                    .collect::<Vec<_>>()
                    .join("\n");
                Some(html)
            }
            _ => None,
        }
    }
}

/// 插件管理器——使用 trait 对象存储异构插件
struct PluginManager {
    plugins: Vec<Box<dyn Plugin>>,
}

impl PluginManager {
    fn new() -> Self {
        Self { plugins: Vec::new() }
    }

    fn register(&mut self, plugin: Box<dyn Plugin>) {
        println!("Registered plugin: {}", plugin.meta().name);
        self.plugins.push(plugin);
    }

    fn load_all(&mut self) {
        for plugin in &mut self.plugins {
            if let Err(e) = plugin.on_load() {
                eprintln!("Failed to load {}: {}", plugin.meta().name, e);
            }
        }
    }

    fn broadcast_event(&self, event: &str, payload: &str) -> Vec<String> {
        self.plugins
            .iter()
            .filter_map(|p| p.handle_event(event, payload))
            .collect()
    }
}

fn main() {
    let mut manager = PluginManager::new();
    manager.register(Box::new(MarkdownPlugin::new()));
    manager.load_all();

    let results = manager.broadcast_event("render", "# Hello\n## World\nThis is Hive.");
    for html in results {
        println!("{}", html);
    }
}
```

`trait Plugin: Any + Send + Sync` 的意思是：**任何实现 `Plugin` 的类型，也必须同时实现 `Any`、`Send` 和 `Sync`。** 冒号后面的这些 trait 叫做 **supertrait**，可以理解为“实现插件接口的前置能力要求”，不是传统面向对象里的字段继承。

拆开看：

| 约束 | 含义 | 为什么插件需要它 |
|------|------|------------------|
| `Any` | 支持运行时类型识别和向下转型 | 插件管理器有时需要把 `dyn Plugin` 还原成具体插件类型 |
| `Send` | 值可以安全地移动到另一个线程 | Tauri/Rust 桌面应用常把任务分发到后台线程 |
| `Sync` | `&T` 可以安全地被多个线程共享 | 插件可能被多个命令、事件或窗口同时读取 |

等价地说，下面这个函数只有在 `P` 同时满足四个 trait 时才接受它：

```rust
fn register_plugin<P>(plugin: P)
where
    P: Plugin + Any + Send + Sync,
{
    // 保存到插件管理器
}
```

但把约束写在 trait 定义上更集中：`PluginManager` 只要处理 `Box<dyn Plugin>`，就能默认相信插件具备这些线程安全和类型识别能力。

```rust
use std::any::Any;

trait RuntimePlugin: Any + Send + Sync {
    fn name(&self) -> &str;

    // 常见写法：暴露 Any 引用，便于需要时做 downcast
    fn as_any(&self) -> &dyn Any;
}

struct SpellCheckPlugin;

impl RuntimePlugin for SpellCheckPlugin {
    fn name(&self) -> &str {
        "spell-check"
    }

    fn as_any(&self) -> &dyn Any {
        self
    }
}

fn try_downcast(plugin: &dyn RuntimePlugin) {
    if plugin.as_any().is::<SpellCheckPlugin>() {
        println!("这是拼写检查插件");
    }
}
```

如果某个插件内部用了不能跨线程共享的类型，例如 `Rc<RefCell<T>>`，它就不会满足 `Send + Sync`。这不是坏事，而是编译器在提醒你：这个插件不能安全地放进多线程插件系统。通常可以改用 `Arc<Mutex<T>>` 或 `Arc<RwLock<T>>`。

```mermaid
classDiagram
    class Plugin {
        <<trait>>
        +meta() PluginMeta
        +on_load() Result
        +on_unload() Result
        +handle_event(event, payload) Option~String~
    }
    class MarkdownPlugin {
        -meta: PluginMeta
        -loaded: bool
        +new() Self
    }
    class PluginManager {
        -plugins: Vec~Box~dyn Plugin~~
        +register(plugin)
        +load_all()
        +broadcast_event(event, payload) Vec~String~
    }

    Plugin <|.. MarkdownPlugin : impl
    PluginManager o-- Plugin : manages
```

---

## 6.8 本章小结

| 概念 | 关键点 |
|------|--------|
| **Trait** | 定义共享行为，类似 Java interface，但可为外部类型实现 |
| **方法接收者** | `&self` 只读借用，`&mut self` 可变借用，`self` 消费对象 |
| **泛型 + Trait Bound** | 静态分发，零成本抽象，编译时单态化 |
| **dyn Trait** | 动态分发，通过 vtable 实现，支持异构集合 |
| **Supertrait** | `trait Plugin: Any + Send + Sync` 表示实现者必须同时满足这些约束 |
| **关联类型** | 一个类型对 trait 只有一种实现时使用 |
| **对象安全** | 使用 `dyn Trait` 时，trait 的方法不能有泛型参数或返回 `Self` |
| **标准库 Trait** | `Debug`、`Display`、`Clone`、`From`、`Iterator` 等是 Rust 生态的基石 |

### 思考题

1. 为什么 `Clone` trait 不是对象安全的？如果你需要克隆一个 `Box<dyn MyTrait>`，该怎么设计？
2. 在什么场景下你会选择 `dyn Trait`（动态分发）而不是泛型（静态分发）？
3. 尝试为 Hive 项目添加一个 `WordCountPlugin`，统计给定文本的字数。

---

> **下一章预告**：第七章我们将深入 Rust 的错误处理哲学——为什么 Rust 没有异常？`Result` 和 `?` 操作符如何让错误处理既安全又优雅？
