默认实现
本课属于 Coddy Rust 学习旅程的“面向对象编程”单元。第 31 课,共 61 课。
到目前为止,我们定义的每个 trait 方法都只有签名:这是一个没有函数体的要求。但如果大多数实现某个 trait 的类型都会使用相同的逻辑呢?Rust 允许你直接在 trait 定义中提供默认实现。
你不再用分号结束方法签名,而是添加方法体:
trait Greet {
fn greet(&self) -> String {
String::from("Hello there!")
}
}
现在,任何实现了 Greet 的类型都会自动获得这个方法,无需在 impl 块中编写任何代码:
struct Guest;
impl Greet for Guest {}
let visitor = Guest;
println!("{}", visitor.greet()); // 你好!
空的 impl Greet for Guest {} 是有效的,因为该特征已经提供了相关行为。这个结构体只需“选择加入”该特征,就能免费获得默认方法。
当你想定义适用于大多数情况的共享行为时,这种模式很有用。需要不同实现的类型可以覆盖默认行为(你将在下一课中学习),而适用标准行为的类型则不必重复编写。
挑战
简单让我们通过构建一个通知系统,来探索默认实现的强大之处!你将创建一个提供开箱即用的标准行为的特征,这样类型就能直接采用这些行为,无需编写重复的代码。
你将把代码分放在三个文件中:
notifiable.rs:定义一个公开的Notifiable特征,其中包含一个具有默认实现的notify(&self) -> String方法。默认实现应返回"You have a new notification!"。任何实现了此特征的类型都会自动获得这种行为,无需在其 impl 块中编写任何内容。alerts.rs:创建两个实现此特征的简单公开单元结构体:EmailAlert:通过空 impl 块实现Notifiable(使用默认实现)SystemAlert:同样通过空 impl 块实现Notifiable(使用默认实现)
main.rs:整合各个模块,并演示这两种警报类型如何共享相同的默认行为。创建这两个结构体的实例,并调用它们的notify方法。
在主文件中,创建一个 EmailAlert 和一个 SystemAlert,然后将它们的通知分别打印在单独的行上。
你的输出应为:
You have a new notification!
You have a new notification!注意,这两种类型会生成完全相同的输出:这就是默认实现的妙处!这两个结构体都不需要为 notify 方法编写任何代码,却都拥有了完整可用的通知行为。在下一课中,你将学习如何在类型需要自定义行为时覆盖这些默认实现。
亲手试试
mod notifiable;
mod alerts;
use notifiable::Notifiable;
use alerts::{EmailAlert, SystemAlert};
fn main() {
// TODO:创建一个 EmailAlert 实例
// TODO:创建一个 SystemAlert 实例
// TODO:打印来自 EmailAlert 的通知
// TODO:打印来自 SystemAlert 的通知
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Rust 在线编译器