Trait
Trait 类似于其他语言中的接口(interface),定义共享行为。
定义 Trait
pub trait Summary {
fn summarize(&self) -> String;
}
pub struct NewsArticle {
pub headline: String,
pub content: String,
}
impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}: {}", self.headline, self.content)
}
}
fn main() {
let article = NewsArticle {
headline: String::from("重大新闻"),
content: String::from("内容详情"),
};
println!("{}", article.summarize());
}
默认实现
pub trait Summary {
fn summarize(&self) -> String {
String::from("(阅读更多...)") // 默认实现
}
}
impl Summary for NewsArticle {} // 使用默认实现
Trait 作为参数
// impl Trait 语法
pub fn notify(item: &impl Summary) {
println!("快讯!{}", item.summarize());
}
// Trait bound 语法(更灵活)
pub fn notify<T: Summary>(item: &T) {
println!("快讯!{}", item.summarize());
}
// 多个 trait 约束
pub fn notify<T: Summary + Display>(item: &T) {
// ...
}
// where 子句
pub fn notify<T>(item: &T)
where
T: Summary + Display,
{
// ...
}
返回实现 Trait 的类型
fn returns_summarizable() -> impl Summary {
NewsArticle {
headline: String::from("标题"),
content: String::from("内容"),
}
}
Trait 关系可视化
孤儿规则
只有当 trait 或类型至少有一个在本地 crate 时,才能为类型实现 trait:
// ✅ 可以:为本地类型实现标准库 trait
impl Display for MyStruct { }
// ✅ 可以:为标准库类型实现本地 trait
impl MyTrait for Vec<i32> { }
// ❌ 不可以:为外部类型实现外部 trait
impl Display for Vec<i32> { } // 编译错误
标准库常用 Trait
Clone 和 Copy
#[derive(Clone, Copy)]
struct Point {
x: i32,
y: i32,
}
Debug 和 Display
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
use std::fmt;
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
PartialEq 和 Eq
#[derive(PartialEq, Eq)]
struct Point {
x: i32,
y: i32,
}
Trait 对象
pub trait Draw {
fn draw(&self);
}
pub struct Screen {
pub components: Vec<Box<dyn Draw>>, // Trait 对象
}
impl Screen {
pub fn run(&self) {
for component in self.components.iter() {
component.draw();
}
}
}
静态分发 vs 动态分发:
impl Trait:静态分发,编译时确定,零开销dyn Trait:动态分发,运行时确定,有虚表开销
关联类型
pub trait Iterator {
type Item; // 关联类型
fn next(&mut self) -> Option<Self::Item>;
}
Trait 继承
trait OutlinePrint: fmt::Display {
fn outline_print(&self) {
println!("* {} *", self); // 可以使用 Display 的 to_string
}
}
小结
- ✅ Trait 定义共享行为
- ✅ 可以有默认实现
- ✅ 使用
impl Trait或 Trait bound 作为参数 - ✅
dyn Trait实现动态分发 - ✅ 孤儿规则防止冲突
- ✅ 标准库提供了许多常用 Trait