Trait 定义了类型可以共享的行为。可以使用 trait 以抽象的方式定义共享行为,使用 trait 约束指定泛型类型必须具有特定行为。
注意: Trait 类似其他语言中的接口(interface),但有一些区别。
1. 定义 Trait 1.1 基本语法 1 2 3 pub trait Summary { fn summarize (&self ) -> String ; }
trait 使用 trait 关键字定义,方法签名以分号结尾。
1.2 多个方法 1 2 3 4 pub trait Summary { fn summarize (&self ) -> String ; fn author (&self ) -> String ; }
2. 实现 Trait 2.1 为类型实现 trait 1 2 3 4 5 6 7 8 9 10 11 12 pub struct NewsArticle { pub headline: String , pub location: String , pub author: String , pub content: String , } impl Summary for NewsArticle { fn summarize (&self ) -> String { format! ("{}, by {} ({})" , self .headline, self .author, self .location) } }
2.2 为另一个类型实现 1 2 3 4 5 6 7 8 9 10 11 12 pub struct Tweet { pub username: String , pub content: String , pub reply: bool , pub retweet: bool , } impl Summary for Tweet { fn summarize (&self ) -> String { format! ("{}: {}" , self .username, self .content) } }
2.3 使用 trait 1 2 3 4 5 6 7 8 9 10 fn main () { let tweet = Tweet { username: String ::from ("horse_ebooks" ), content: String ::from ("of course, as you probably already know" ), reply: false , retweet: false , }; println! ("1 new tweet: {}" , tweet.summarize ()); }
3. 默认实现 3.1 提供默认行为 1 2 3 4 5 pub trait Summary { fn summarize (&self ) -> String { String ::from ("(Read more...)" ) } }
3.2 使用默认实现 1 2 3 4 5 6 7 8 9 10 11 12 impl Summary for NewsArticle {} fn main () { let article = NewsArticle { headline: String ::from ("Penguins win the Stanley Cup Championship!" ), location: String ::from ("Pittsburgh, PA, USA" ), author: String ::from ("Iceburgh" ), content: String ::from ("The Pittsburgh Penguins once again are the best..." ), }; println! ("New article: {}" , article.summarize ()); }
3.3 默认实现调用其他方法 1 2 3 4 5 6 7 pub trait Summary { fn summarize_author (&self ) -> String ; fn summarize (&self ) -> String { format! ("(Read more from {}...)" , self .summarize_author ()) } }
4. Trait 作为参数 4.1 impl Trait 语法 1 2 3 pub fn notify (item: &impl Summary ) { println! ("Breaking news! {}" , item.summarize ()); }
4.2 Trait Bound 语法 1 2 3 pub fn notify <T: Summary>(item: &T) { println! ("Breaking news! {}" , item.summarize ()); }
4.3 多个 trait 约束 1 2 3 4 5 6 7 8 pub fn notify (item: &(impl Summary + Display)) { } pub fn notify <T: Summary + Display>(item: &T) { }
4.4 where 子句 1 2 3 4 5 6 7 fn some_function <T, U>(t: &T, u: &U) -> i32 where T: Display + Clone , U: Clone + Debug , { }
5. 返回实现 Trait 的类型 1 2 3 4 5 6 7 8 fn returns_summarizable () -> impl Summary { Tweet { username: String ::from ("horse_ebooks" ), content: String ::from ("of course, as you probably already know" ), reply: false , retweet: false , } }
限制: 只能返回单一类型,不能根据条件返回不同类型。
6. 孤儿规则 只有当 trait 或类型至少有一个是在当前 crate 中定义的,才能为该类型实现 trait。
1 2 3 4 5 impl Summary for Vec <i32 > {}impl Display for Vec <i32 > {}
7. 使用 Trait Bound 有条件地实现方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 use std::fmt::Display;struct Pair <T> { x: T, y: T, } impl <T> Pair<T> { fn new (x: T, y: T) -> Self { Self { x, y } } } impl <T: Display + PartialOrd > Pair<T> { fn cmp_display (&self ) { if self .x >= self .y { println! ("The largest member is x = {}" , self .x); } else { println! ("The largest member is y = {}" , self .y); } } }
8. Blanket Implementations 为所有满足特定 trait bound 的类型实现 trait:
1 2 3 impl <T: Display> ToString for T { }
这意味着任何实现了 Display 的类型都自动实现了 ToString。
总结
定义 trait :使用 trait 关键字定义共享行为
实现 trait :使用 impl Trait for Type 语法
默认实现 :可以在 trait 中提供默认方法实现
trait 参数 :使用 impl Trait 或 trait bound 语法
孤儿规则 :保证 trait 实现的一致性
Trait 是 Rust 实现多态和代码复用的核心机制,配合泛型可以编写灵活且类型安全的代码。
Hooray!特征学习完成!!!