Rust Trait
trait 定义共享行为;impl Trait for Type 提供实现;bound 约束泛型;与接口/类型类的对照。
#type / concept
#status / growing
#tech / dev
#resource / rust
[!info] 关联笔记
Rust Trait
这个概念为什么出现
不同的类型需要同一套能力:可摘要、可序列化、可迭代、可比较。
Rust 不用继承树挂方法,而用 trait 声明行为,再为具体类型实现。
[!abstract] 一句话理解
trait是行为契约;impl Trait for Type提供实现;泛型上的T: Trait把契约变成编译期约束。
最小可运行示例
场景:通知中心——邮件与短信都能 send
运营系统要对用户发通知,渠道不同但都要 send。用 trait 统一调用面。
// 业务意图:统一通知发送接口,屏蔽渠道差异。
// 教学点:trait 定义、为结构体实现、泛型 bound、&dyn Trait 点到为止。
trait Notifier {
fn send(&self, user_id: u64, body: &str);
}
struct EmailNotifier { from: String }
struct SmsNotifier { sender_id: String }
impl Notifier for EmailNotifier {
fn send(&self, user_id: u64, body: &str) {
println!("email from={} user={} body={}", self.from, user_id, body);
}
}
impl Notifier for SmsNotifier {
fn send(&self, user_id: u64, body: &str) {
println!("sms sender={} user={} body={}", self.sender_id, user_id, body);
}
}
// 静态分发:编译期单态化
fn notify_all<N: Notifier>(n: &N, user_id: u64, body: &str) {
n.send(user_id, body);
}
fn main() {
let email = EmailNotifier { from: String::from("noreply@shop") };
let sms = SmsNotifier { sender_id: String::from("SHOP") };
notify_all(&email, 7, "order shipped");
notify_all(&sms, 7, "order shipped");
}
建议运行:cargo run
期望输出:
email from=noreply@shop user=7 body=order shipped
sms sender=SHOP user=7 body=order shipped
结合场景再看三个关注点
- 调用方依赖 trait 而非具体渠道
- 泛型 bound 零成本静态分发
- 需要异构集合时再引入
dyn Notifier(进阶)
核心概念与准确模型
定义与实现
trait Summary {
fn summarize(&self) -> String;
fn prefix(&self) -> String { // 默认实现
String::from("(summary)")
}
}
派生与标准 trait
常见:Debug、Clone、Default、PartialEq、Iterator、From/Into。
约束写法
fn f<T: Clone + Debug>(x: T)where子句更清晰
静态分发 vs 动态分发
- 泛型:
impl Trait/T: Trait→ 单态化 - trait 对象:
dyn Trait→ 虚表,对象安全有限制
设计动机
- 组合行为,避免深层继承
- 孤儿规则等限制保证 trait 实现的一致性
- 与泛型一起支撑零成本抽象
边界与误区
- 不能对外部类型实现外部 trait(孤儿规则)
- 默认方法可重写
- trait 对象方法接收者限制
[!warning] 常见误区:把 trait 当 Java interface 的 1:1 有默认方法、关联类型、泛型方法等更丰富机制;对象安全也不同。
工程实践
- 小而专的 trait 优于上帝接口
- 公共 API 用 trait 隐藏实现
- 能静态分发就不要无
dyn换间接层 - 善用
From/TryFrom做转换契约
本节总结
- trait 定义能力
- impl 提供实现
- bound 约束泛型
- 静态/动态分发按需
自测题
T: Notifier与&dyn Notifier主要差别?- 为什么需要默认实现?
参考答案
- 前者单态化静态分发;后者运行时多态、有对象安全约束。
- 减少样板,同时保留可覆盖点。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| The Book — Traits | 官方书 | trait |
| Rust By Example — Traits | 官方 | 示例 |