Rust 学习笔记 15:Traits (特质)

“If it walks like a duck and quacks like a duck, it must be a Trait.”

在 Go 语言中,接口 (Interface) 是隐式实现的。只要你的方法签名对上了,你就实现了接口。 在 Rust 中,Traits (特质) 必须要显式实现 (impl Trait for Type)。

1. 定义与实现 Trait

定义一个 Summary Trait:

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

NewsArticleTweet 实现它:

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

2. 默认实现 (Default Implementations)

Trait 中可以提供默认实现,这有点像 Java 8 的 default method。

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

如果实现了 Trait 的类型不重写它,就会使用这个默认版本。

3. Trait 作为参数

要想编写接受任何实现了 Summary 的类型的函数,有两种写法。

impl Trait 语法糖

1pub fn notify(item: &impl Summary) { ... }

Trait Bound (泛型约束)

1pub fn notify<T: Summary>(item: &T) { ... }

如果你需要两个参数是同一种类型,必须用 Trait Bound:fn foo<T: Summary>(p1: T, p2: T)

4. 多重约束与 Where 从句

如果一个类型需要同时实现多个 Trait(比如即要能显示,又要能拷贝):

1fn notify(item: &(impl Summary + Display)) { ... }

如果约束太长,函数签名会很丑,可以用 where 从句:

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

5. 孤儿规则 (Orphan Rule)

这是 Rust 为了保证一致性的一条重要规则: 你只能为类型实现 Trait,如果 Trait 或 类型 至少有一个是在你的 Crate 中定义的。

例如:

  • 你可以为如果你自定义的 Tweet 实现标准库的 Display
  • 你可以为标准库的 Vec 实现你自定义的 Summary
  • 但是,你不能为 Vec (标准库) 实现 Display (标准库)。

这防止了其他人破坏你的代码行为(虽然在 Go 中可以通过 alias type 绕过,但 Rust 比较严格)。

6. 小结

第十五篇笔记。

  • Trait 定义了共享行为。
  • impl Trait for Type 显式实现。
  • Trait Bound 是泛型的约束条件。

Trait 是 Rust 零成本抽象的灵魂。标准库中充满了 Trait:Display, Debug, Copy, Clone, Drop, Iterator… 掌握了 Trait,你就掌握了 Rust 的半壁江山。

下一篇,我们将挑战 Rust 的终极 Boss —— 生命周期 (Lifetimes)。这是泛型的一个特例,也是让无数初学者头秃的元凶。


练习题

  1. Pair<T> 结构体实现 new 函数。
  2. 使用 impl<T: Display + PartialOrd> Pair<T> 块,编写一个 cmp_display 方法,只有当 T 实现了 DisplayPartialOrd 时,Pair<T> 才有这个方法(这叫 Blanket Implementation 的一种应用)。

思考题

Go 的接口是"鸭子类型"(只要像鸭子就是鸭子),Rust 的 Trait 是"名义类型"(必须显式声明)。在大型项目中,这两种设计哲学对代码重构和维护有什么不同影响?


本文代码示例

关注公众号:极客老墨

更多 AI 应用开发、工程实践和效率工具分享,欢迎扫码关注。

极客老墨微信公众号二维码

相关阅读