Trait
定义共同行为,trait 定义了某个特定类型拥有可能与其他类型共享的功能。可以通过 trait 以一种抽象的方式定义共同行为。可以使用 trait bounds 指定泛型是任何拥有特定行为的类型。
定义 trait
一个类型的行为由其可供调用的方法构成。如果可以对不同类型调用相同的方法的话,这些类 型就可以共享相同的行为了。trait 定义是一种将方法签名组合起来的方法,目的是定义一个实 现某些目的所必需的行为的集合。
使用 trait 来声明一个 trait,后面是 trait 的名字。大括号中是方法的签名。在方法签名后跟分号而不是大括号及其实现。接着每一个实现这个 trait 的类型都需要提供其自定义行为的方法体,编译器也会确保任何实现 Summary trait 的类型都拥有与这个
签名的定义完全一致的 summarize 方法。
#![allow(unused)] fn main() { pub trait Summary { fn summarize(&self) -> String; } }
实现 trait
当 trait 或者 类型至少有一个属于当前 crate 才能对类型实现该 crate。不能为外部类型实现外部 trait,这个被称为相干性。孤儿规则。
#![allow(unused)] fn main() { pub trait Summary { fn summarize(&self) -> String; } 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) } } 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) } } }
调用 trait
trait 必须和类型一起引入作用域以便使用额外的 trait 方法。
use crate::aggregator::{NewsArticle, Summary, Tweet}; mod aggregator; fn main() { let news_article = NewsArticle{ headline: "Look".to_string(), location: "Shan Xi".to_string(), author: "Han ZhuoXian".to_string(), content: "Look at the man".to_string(), }; println!("news article: {}", news_article.summarize()); let tweet = Tweet { username: "zhuoxian".to_string(), content: "I like you!".to_string(), reply:false, retweet:false, }; println!("tweet: {}", tweet.summarize()); }
默认实现
为方法提供默认行为,为某个类型实现时可以选择覆盖默认行为。
#![allow(unused)] fn main() { pub trait Summary { fn summarize(&self) -> String { "Read from ...".to_string() } } }
Trait 作为参数
#![allow(unused)] fn main() { // Trait Bound 语法 适合更复杂的场景 pub fn notify_bound<T: Summary> (item : &T) { println!("News : {}", item.summarize()); } // &impl 是 Trait Bound 语法的语法糖,适合简短的例子 pub fn notify(item: &impl Summary) { println!("News : {}", item.summarize()); } // 使用 + 指定多个 trait bound pub fn notify_bound_display<T: Summary + Display>(item: &T) { println!("News : {}", item.summarize()); } // 多个 trait bound 的语法糖 pub fn notify_display(item: &(impl Summary + Display)) { println!("News : {}", item.summarize()); } // 使用 where 子句简化函数签名 pub fn some<T, U>(t: &T, u: &U) where T: Display + Clone, U: Clone + Debug, { println!("some {} {:?}", t, u); } }
使用 trait bound 有条件的实现方法
通过使用带有 trait bound 的泛型参数的 impl 块,可以有条件地只为那些实现了特定 trait 的类型实现方法。
use std::fmt::Display; struct Pair<T> { x: T, y: T, } struct Own { } // 为所有 Pair 结构体实现 new 方法 impl<T> Pair<T> { fn new(x: T, y: T) -> Self { Self { x: x, y: y } } } // 限定只有实现 T 实现了 Display 和 PartialOrd 才能使用该方法。 impl<T: Display + PartialOrd> Pair<T> { fn cmp_display(&self) { if self.x >= self.y { println!("x >= y"); } else { println!("x < y"); } } } fn main() { let pair = Pair::new(1, 2); pair.cmp_display(); let o_x = Own{}; let o_y = Own{}; let pair = Pair::new(o_x, o_y); // pair.cmp_display();// 不能调用该方法 }
对任何实现了特定 trait 的类型实现方法 blanket implementations。
#![allow(unused)] fn main() { impl <T: Display> ToString for T { } }