什么是trait?
Trait其实就是告诉编译器:
- 某种类型具有哪些行为,并且这些行为其他的类型也可以拥有(类似于接口interface)
- trait是一个公共行为的签名集合,也就是只声明有哪种行为,不做具体实现
- 利用关键字trait就可以声明一个Trait
```rust
pub trait Summary {
// trait实现的只是一个签名的集合,并不会有具体的实现
fn summarize(&self) -> String
}
pub struct NewsArticle { pub headline: String, pub location: String, pub author: String, pub content: String, }
pub struct Tweet { pub username: String, pub content: String, pub reply: bool, pub retweet: bool, }
// 为结构体实现trait,这里就是trait中签名的具体实现 impl Summary for NewsArticle { fn summarize(&self) -> String { format!(“{},作者{}({})”, self.headline, self.author, self.location) } }
impl Summary for Tweet { fn summarize(&self) -> String { format!(“{},用户名:{}”, self.content, self.username) }
}
从上面的例子可以看出:
- Summary作为一个trait,定义了一个行为summarize
- 这个行为结构体NesArticle和Tweet都可以拥有
<a name="daYqU"></a>
## 默认行为
- 默认行为:我们在定义trait的签名时,是可以给一个默认实现的
- 默认实现中可以调用当前trait中的方法,即使这个方法是没有默认实现的
- 默认行为可以通过在具体类型中实现trait时给重写掉
基于上面的例子我们来看下
```rust
pub trait Summary {
fn get_user(&self) -> String;
// 这里就是默认实现,并且调用了自身的get_user这个方法,并且这个方法没有默认实现
fn summarize(&self) -> String {
format!("这是默认实现的trait,详情查看{}", self.get_user())
}
}
pub struct NewsArticle {
pub headline: String,
pub location: String,
pub author: String,
pub content: String,
}
pub struct Tweet {
pub username: String,
pub content: String,
pub reply: bool,
pub retweet: bool,
}
// 为结构体实现trait,这里就是trait中签名的具体实现
impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{},作者{}({})", self.headline, self.author, self.location)
}
fn get_user(&self) -> String {
format!("{}", self.author)
}
}
impl Summary for Tweet {
// fn summarize(&self) -> String {
// format!("{},用户名:{}", self.content, self.username)
// }
fn get_user(&self) -> String {
format!("{}", self.username)
}
}
let tweet = Tweet {
username: String::from("horse_ebooks"),
content: String::from("of course, as you probably already know, people"),
reply: false,
retweet: false,
};
// 调用该trait的方法
println!("1 new tweet: {}", tweet.summarize());
trait作为参数
trait作为参数的意思就是:
这个参数是实现了某个trait的这样一个结构
trait作为参数有两种方式:
- impl XXX
- Trait bound
我们基于上面的例子继续来解读一下:
我们需要实现一个notify方法,这个方法的参数item需要是实现了Summary这个trait的结构
impl trait
// 第一种方法
pub fn notify(item: impl Summary) {
print!("爆炸新闻来袭!{}", item.summarize());
}
Trait bound
- Trait bounds:可以将泛型的类型绑定为某些trait
// 将类型T绑定为实现了 Summary 这个trait的这样一个类型 pub fn notify<T: Summary>(item: T) { print!("爆炸新闻来袭!{}", item.summarize()); }
利用+来绑定多来trait
如果现在的需求是一个类型是Summary和Copy这两个trait实现的类型呢?
pub fn notify<T: Summary + Copy>(item: T) {
print!("爆炸新闻来袭!{}", item.summarize());
}
当然这样如果是trait过多的话,就会造成函数的签名看起来很繁琐,所以rust提供了一个where给我们使用。
使用where简化多个绑定
where写在返回值类型的后面即可
pub fn notify<T, U>(item: T, item2: U)
where
T: Summary + Copy,
U: xxxx + yyyy,
{
print!("爆炸新闻来袭!{}", item.summarize());
}