Trait 高级特性
> 掌握 impl Trait 返回类型、条件实现和 blanket implementation 等高级用法。
返回实现 Trait 的类型
impl Trait 返回类型
rust
▶ Runpub trait Summary {
fn summarize(&self) -> String;
}
// 返回实现 Summary 的类型
fn returns_summarizable() -> impl Summary {
Tweet {
username: String::from("horse_ebooks"),
content: String::from("of course"),
}
}
fn main() {
let item = returns_summarizable();
println!("{}", item.summarize());
}限制:只能返回单一类型
rust
▶ Run// ❌ 错误:返回了不同类型
// fn returns_summarizable(switch: bool) -> impl Summary {
// if switch {
// Tweet { /* ... */ }
// } else {
// NewsArticle { /* ... */ }
// }
// }
// ✅ 正确:使用 Trait 对象(Box)
fn returns_summarizable(switch: bool) -> Box<dyn Summary> {
if switch {
Box::new(Tweet {
username: String::from("horse_ebooks"),
content: String::from("of course"),
})
} else {
Box::new(NewsArticle {
headline: String::from("Breaking"),
location: String::from("NYC"),
author: String::from("John"),
content: String::from("..."),
})
}
}impl Trait vs Box<dyn Trait>
┌─────────────────────────────────────────────────────┐
│ impl Trait vs Box<dyn Trait> │
├─────────────────────────────────────────────────────┤
│ │
│ impl Trait(静态分发) │
│ ├── 编译时确定类型 │
│ ├── 零运行时开销 │
│ ├── 只能返回单一类型 │
│ └── 更高效的调用 │
│ │
│ Box<dyn Trait>(动态分发) │
│ ├── 运行时确定类型 │
│ ├── 有小开销(虚函数表查找) │
│ ├── 可以返回不同类型 │
│ └── 更灵活 │
│ │
│ 选择: │
│ • 需要返回不同类型 → Box<dyn Trait> │
│ • 追求性能 → impl Trait │
│ │
└─────────────────────────────────────────────────────┘条件实现
基于泛型约束的实现
rust
▶ Runuse std::fmt::Display;
struct Pair<T> {
x: T,
y: T,
}
impl<T> Pair<T> {
fn new(x: T, y: T) -> Self {
Self { x, y }
}
}
// 只有当 T 实现 Display + PartialOrd 时,Pair<T> 才有这个方法
impl<T: Display + PartialOrd> Pair<T> {
fn cmp_display(&self) {
if self.x >= self.y {
println!("较大的是 x: {}", self.x);
} else {
println!("较大的是 y: {}", self.y);
}
}
}
// 为所有 T 实现 Debug
impl<T: std::fmt::Debug> Pair<T> {
fn debug_print(&self) {
println!("{:?}", self);
}
}
fn main() {
let p1 = Pair { x: 5, y: 10 };
p1.cmp_display(); // 较大的是 y: 10
p1.debug_print(); // Pair { x: 5, y: 10 }
let p2 = Pair { x: 1.0, y: 2.0 };
p2.cmp_display(); // 较大的是 y: 2.0
}blanket implementation
rust
▶ Run// 为所有实现 Summary 的类型实现 toString
trait Summary {
fn summarize(&self) -> String;
}
trait ToString {
fn to_string(&self) -> String;
}
// 为所有实现 Summary 的类型自动实现 ToString
impl<T: Summary> ToString for T {
fn to_string(&self) -> String {
self.summarize()
}
}
---
## 小结
- `impl Trait` 作为返回类型,只能返回单一具体类型
- `Box<dyn Trait>` 可以返回不同类型,但有运行时开销
- 条件实现为满足约束的类型提供特定方法
- blanket implementation 为所有实现某 trait 的类型自动实现另一个 trait
- 静态分发优先,动态分发灵活
## 练习题
详见:[练习题](../../exercises/16-traits)