Skip to content

Trait 基础

> 理解 Trait 的核心概念和价值,学会定义和实现 Trait,对比 Rust 与其他语言的接口机制。

为什么需要 Trait?深度解析

Trait 语法

概念名称: Trait 定义共享行为,类似其他语言的接口。

语法结构:
┌──────────────────────────────────────┐
│  trait Trait名 {                      │
│      fn 方法名(&self) -> 返回类型;    │
│  }                                    │
│                                       │
│  impl Trait名 for 类型 {              │
│      fn 方法名(&self) -> 返回类型 {   │
│          实现...                       │
│      }                                │
│  }                                    │
│                                       │
│  trait Summary {                      │
│      fn summarize(&self) -> String;  │
│  }                                    │
│                                       │
│  impl Summary for Article { ... }    │
└──────────────────────────────────────┘

最简示例

rust
trait Speak {
    fn say(&self) -> String;
}

struct Dog;
impl Speak for Dog {
    fn say(&self) -> String { "汪".to_string() }
}

fn main() {
    let dog = Dog;
    println!("{}", dog.say());
}
▶ Run

从代码组织问题出发

rust
// 问题:不同类型的相似操作,无法统一处理

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

impl NewsArticle {
    fn get_summary(&self) -> String {
        format!("{}, by {}", self.headline, self.author)
    }
}

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

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

// ❌ 无法编写通用函数
// fn print_summary(item: ???) {
//     println!("{}", item.get_summary());
// }

// 只能写两个函数:
fn print_article_summary(article: &NewsArticle) {
    println!("{}", article.get_summary());
}

fn print_tweet_summary(tweet: &Tweet) {
    println!("{}", tweet.get_summary());
}
▶ Run

问题本质:

┌─────────────────────────────────────────────────────┐
│           代码组织困境                               │
├─────────────────────────────────────────────────────┤
│                                                     │
│  NewsArticle                                        │
│  ┌─────────────────────────┐                       │
│  │ get_summary(&self)      │                       │
│  │ -> String               │                       │
│  └─────────────────────────┘                       │
│                                                     │
│  Tweet                                              │
│  ┌─────────────────────────┐                       │
│  │ get_summary(&self)      │                       │
│  │ -> String               │                       │
│  └─────────────────────────┘                       │
│                                                     │
│  问题:                                              │
│  • 方法签名相同,但类型不同                          │
│  • 无法编写统一的处理函数                            │
│  • 每种类型都需要单独实现                            │
│  • 代码重复,维护困难                                │
│                                                     │
│  Java/C++ 的解决方案:                               │
│  • 使用继承(父类定义共同方法)                      │
│  • 但 Rust 不支持继承                                │
│                                                     │
│  Rust 的解决方案:                                    │
│  • Trait 定义共享行为                                │
│  • 组合优于继承                                      │
│                                                     │
└─────────────────────────────────────────────────────┘

Trait 的解决方案

rust
// ✅ 使用 Trait 定义共享行为
trait Summary {
    fn get_summary(&self) -> String;
}

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

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

// ✅ 现在可以编写通用函数
fn print_summary(item: &impl Summary) {
    println!("{}", item.get_summary());
}

fn main() {
    let article = NewsArticle {
        headline: String::from("Breaking News"),
        author: String::from("John"),
        content: String::from("..."),
    };

    let tweet = Tweet {
        username: String::from("@rustlang"),
        content: String::from("Hello world!"),
    };

    print_summary(&article);  // Breaking News, by John
    print_summary(&tweet);    // @rustlang: Hello world!
}
▶ Run

Trait 内存布局:

Trait 的内存模型:

┌─────────────────────────────────────────────────────┐
│           Trait 不是数据,是行为的抽象               │
├─────────────────────────────────────────────────────┤
│                                                     │
│  Trait 定义:                                        │
│  trait Summary {                                    │
│      fn get_summary(&self) -> String;              │
│  }                                                  │
│                                                     │
│  NewsArticle 实例(栈):                             │
│  ┌─────────────────────────┐                       │
│  │ headline: String        │                       │
│  │ author: String          │                       │
│  │ content: String         │                       │
│  └─────────────────────────┘                       │
│           ↓                                         │
│  impl Summary for NewsArticle                      │
│  ┌─────────────────────────┐                       │
│  │ get_summary 方法实现     │ ← 编译时确定          │
│  │ 访问 self.headline      │   (静态分发)        │
│  │ 访问 self.author        │                       │
│  └─────────────────────────┘                       │
│                                                     │
│  Tweet 实例(栈):                                  │
│  ┌─────────────────────────┐                       │
│  │ username: String        │                       │
│  │ content: String         │                       │
│  └─────────────────────────┘                       │
│           ↓                                         │
│  impl Summary for Tweet                            │
│  ┌─────────────────────────┐                       │
│  │ get_summary 方法实现     │ ← 编译时确定          │
│  │ 访问 self.username      │   (静态分发)        │
│  │ 访问 self.content       │                       │
│  └─────────────────────────┘                       │
│                                                     │
│  Trait 不占用额外内存                                │
│  • 只是方法的集合                                    │
│  • 实现时绑定到具体类型                              │
│  • 调用时编译器确定具体方法                          │
│                                                     │
└─────────────────────────────────────────────────────┘

Trait 的核心作用

┌─────────────────────────────────────────────────────┐
│              Trait 的核心作用                        │
├─────────────────────────────────────────────────────┤
│                                                     │
│  1. 抽象行为(接口)                                 │
│     • 定义一组方法的签名                            │
│     • 不关心具体实现                                │
│     • 类似其他语言的 interface                      │
│                                                     │
│  2. 泛型约束                                        │
│     • 限制泛型参数的可用方法                        │
│     • 编译时类型检查                                │
│     • 零运行时开销                                  │
│                                                     │
│  3. 代码复用                                        │
│     • 默认实现减少重复代码                         │
│     • 为现有类型添加行为(扩展)                   │
│     • 组合优于继承                                  │
│                                                     │
│  4. 多态支持                                        │
│     • Trait 对象(动态分发)                        │
│     • 运行时可以选择不同实现                        │
│     • 灵活但有小开销                                │
│                                                     │
└─────────────────────────────────────────────────────┘



---

## 小结

- Trait 定义共享行为,类似其他语言的接口
- `trait Name { fn method(); }` 定义 Trait,`impl Trait for Type` 实现
- Trait 的核心作用:抽象行为、泛型约束、代码复用、多态支持
- Trait 不占用额外内存,是方法的抽象集合
- 组合优于继承,Rust 用 Trait 实现多态

## 练习题

详见:[练习题](../../exercises/16-traits)