Trait 特征
学习目标
- 定义和实现 trait
- 理解默认实现
- 掌握 trait 作为参数
- 理解孤儿规则
核心概念
定义 Trait
trait Summary {
fn summarize(&self) -> String;
}
struct Article {
title: String,
author: String,
content: String,
}
impl Summary for Article {
fn summarize(&self) -> String {
format!("{}, 作者 {}", self.title, self.author)
}
}
struct Tweet {
username: String,
content: String,
}
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("@{}: {}", self.username, self.content)
}
}
fn main() {
let article = Article {
title: String::from("Rust 入门"),
author: String::from("Alice"),
content: String::from("..."),
};
println!("{}", article.summarize());
}
默认实现
trait Summary {
fn summarize(&self) -> String {
String::from("(阅读更多...)")
}
}
struct EmptyArticle;
impl Summary for EmptyArticle {}
fn main() {
let a = EmptyArticle;
println!("{}", a.summarize());
}
Trait 作为参数
fn notify(item: &impl Summary) {
println!("速报: {}", item.summarize());
}
fn notify<T: Summary>(item: &T) {
println!("速报: {}", item.summarize());
}
fn notify(item: &(impl Summary + std::fmt::Display)) { }
fn notify<T: Summary + std::fmt::Display>(item: &T) { }
返回 impl Trait
fn create_summarizable() -> impl Summary {
Tweet {
username: String::from("rust"),
content: String::from("Rust 1.0 发布!"),
}
}
Trait 对象(动态分发)
trait Animal {
fn speak(&self) -> String;
}
struct Dog;
struct Cat;
impl Animal for Dog {
fn speak(&self) -> String { String::from("汪汪") }
}
impl Animal for Cat {
fn speak(&self) -> String { String::from("喵喵") }
}
fn main() {
let animals: Vec<Box<dyn Animal>> = vec![
Box::new(Dog),
Box::new(Cat),
Box::new(Dog),
];
for animal in &animals {
println!("{}", animal.speak());
}
}
孤儿规则
trait MyTrait { }
struct MyType;
impl MyTrait for MyType { }
impl std::fmt::Display for MyType {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "MyType")
}
}
常用标准库 Trait
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct Point {
x: i32,
y: i32,
}
impl std::fmt::Display for Point {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
fn main() {
let p = Point { x: 1, y: 2 };
println!("{}", p);
println!("{:?}", p);
let p2 = p.clone();
assert_eq!(p, p2);
}
实践练习
练习 1:可打印
trait Printable {
fn print(&self);
fn format(&self) -> String;
}
impl Printable for i32 {
fn print(&self) { println!("{}", self); }
fn format(&self) -> String { format!("i32: {}", self) }
}
impl Printable for String {
fn print(&self) { println!("{}", self); }
fn format(&self) -> String { format!("String: \"{}\"", self) }
}
fn print_all(items: &[&dyn Printable]) {
for item in items {
item.print();
}
}
fn main() {
let items: Vec<&dyn Printable> = vec![&42, &String::from("hello")];
print_all(&items);
}
练习 2:可比较
trait MaxValue {
fn max_value() -> Self;
}
impl MaxValue for i32 {
fn max_value() -> Self { i32::MAX }
}
impl MaxValue for f64 {
fn max_value() -> Self { f64::MAX }
}
fn main() {
println!("i32 max: {}", i32::max_value());
println!("f64 max: {}", f64::max_value());
}
常见错误
1. 未实现所有方法
trait MyTrait {
fn a();
fn b();
}
struct Foo;
2. 孤儿规则违反
小结
| 概念 | 说明 |
|---|
trait | 定义共享行为 |
impl Trait for Type | 为类型实现 trait |
impl Trait | 参数/返回值的 trait 约束 |
dyn Trait | trait 对象(动态分发) |
| 孤儿规则 | 至少一个类型是本地的 |
#[derive(...)] | 自动派生常用 trait |