trait(特征)被用来向rust编译器描述某些特定类型拥有的且能够被其他类型共享的功能,它使我们可以以一种抽象的方式来定义共享行为。我们还可以使用trait约束来将泛型参数指定为实现了某些特定行为的类型。
定义trait
定义一个trait:
pub trait Summary {
fn summarize(&self) -> String;
}
在trait中定义方法签名,可以定义多个方法签名。
为类型实现trait
#![allow(unused_variables)]
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需要在impl关键字后提供我们想要实现的trait名,并紧接这for关键字及当前的类型名。在impl代码块中,我们同样需要填入trait中的方法,在花括号中实现针对该结构体的函数体。
如何我们便可以基于实例调用该trait的方法了:
use chapter10::{self, Summary, Tweet};
fn main() {
let tweet = Tweet {
username: String::from("horse_ebooks"),
content: String::from(
"of course, as you probably already know, people",
),
reply: false,
retweet: false,
};
println!("1 new tweet: {}", tweet.summarize());
}
trait有一个限制:只有当trait或类型定义于我们的库中时,我们才能为该类型实现对应的trait。
我们不能为外部类实现外部trait,这个限制被称为孤儿规则,因为他的父类型没有定义在当前库中。这一规则也是程序一致性的组成部分,确保了其他所有的人所编写的内容不会破坏到你的代码。如果没有这个规则,那么两个库可以分别对相同的类型实现相同的trait,rust无法确定使用哪一个版本。
默认实现
trait可以提供一个默认的实现,这样使用trait的类型就不用非要自己写实现了:
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("{}: {}", self.username, self.content)
}
}
语法上就是把签名的分号去掉,任何在花括号中写上函数体即可。