Rust —— 特征

Trait 定义了类型可以共享的行为。可以使用 trait 以抽象的方式定义共享行为,使用 trait 约束指定泛型类型必须具有特定行为。

注意: Trait 类似其他语言中的接口(interface),但有一些区别。

1. 定义 Trait

1.1 基本语法

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

trait 使用 trait 关键字定义,方法签名以分号结尾。

1.2 多个方法

1
2
3
4
pub trait Summary {
fn summarize(&self) -> String;
fn author(&self) -> String;
}

2. 实现 Trait

2.1 为类型实现 trait

1
2
3
4
5
6
7
8
9
10
11
12
pub struct NewsArticle {
pub headline: String,
pub location: String,
pub author: String,
pub content: String,
}

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

2.2 为另一个类型实现

1
2
3
4
5
6
7
8
9
10
11
12
pub struct Tweet {
pub username: String,
pub content: String,
pub reply: bool,
pub retweet: bool,
}

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

2.3 使用 trait

1
2
3
4
5
6
7
8
9
10
fn main() {
let tweet = Tweet {
username: String::from("horse_ebooks"),
content: String::from("of course, as you probably already know"),
reply: false,
retweet: false,
};

println!("1 new tweet: {}", tweet.summarize());
}

3. 默认实现

3.1 提供默认行为

1
2
3
4
5
pub trait Summary {
fn summarize(&self) -> String {
String::from("(Read more...)")
}
}

3.2 使用默认实现

1
2
3
4
5
6
7
8
9
10
11
12
impl Summary for NewsArticle {}  // 使用默认实现

fn main() {
let article = NewsArticle {
headline: String::from("Penguins win the Stanley Cup Championship!"),
location: String::from("Pittsburgh, PA, USA"),
author: String::from("Iceburgh"),
content: String::from("The Pittsburgh Penguins once again are the best..."),
};

println!("New article: {}", article.summarize()); // (Read more...)
}

3.3 默认实现调用其他方法

1
2
3
4
5
6
7
pub trait Summary {
fn summarize_author(&self) -> String;

fn summarize(&self) -> String {
format!("(Read more from {}...)", self.summarize_author())
}
}

4. Trait 作为参数

4.1 impl Trait 语法

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

4.2 Trait Bound 语法

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

4.3 多个 trait 约束

1
2
3
4
5
6
7
8
pub fn notify(item: &(impl Summary + Display)) {
// ...
}

// 或使用 trait bound
pub fn notify<T: Summary + Display>(item: &T) {
// ...
}

4.4 where 子句

1
2
3
4
5
6
7
fn some_function<T, U>(t: &T, u: &U) -> i32
where
T: Display + Clone,
U: Clone + Debug,
{
// ...
}

5. 返回实现 Trait 的类型

1
2
3
4
5
6
7
8
fn returns_summarizable() -> impl Summary {
Tweet {
username: String::from("horse_ebooks"),
content: String::from("of course, as you probably already know"),
reply: false,
retweet: false,
}
}

限制: 只能返回单一类型,不能根据条件返回不同类型。

6. 孤儿规则

只有当 trait 或类型至少有一个是在当前 crate 中定义的,才能为该类型实现 trait。

1
2
3
4
5
// ✅ 可以:Summary 在当前 crate 定义
impl Summary for Vec<i32> {}

// ❌ 不行:Display 和 Vec 都在标准库中
impl Display for Vec<i32> {}

7. 使用 Trait Bound 有条件地实现方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use std::fmt::Display;

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

impl<T> Pair<T> {
fn new(x: T, y: T) -> Self {
Self { x, y }
}
}

impl<T: Display + PartialOrd> Pair<T> {
fn cmp_display(&self) {
if self.x >= self.y {
println!("The largest member is x = {}", self.x);
} else {
println!("The largest member is y = {}", self.y);
}
}
}

8. Blanket Implementations

为所有满足特定 trait bound 的类型实现 trait:

1
2
3
impl<T: Display> ToString for T {
// ToString 实现
}

这意味着任何实现了 Display 的类型都自动实现了 ToString

总结

  • 定义 trait:使用 trait 关键字定义共享行为
  • 实现 trait:使用 impl Trait for Type 语法
  • 默认实现:可以在 trait 中提供默认方法实现
  • trait 参数:使用 impl Trait 或 trait bound 语法
  • 孤儿规则:保证 trait 实现的一致性

Trait 是 Rust 实现多态和代码复用的核心机制,配合泛型可以编写灵活且类型安全的代码。

Hooray!特征学习完成!!!