Trait 告诉编译器
某种类型具有那些并且可以与其他类型共享的功能
它的本质就是
不同类型具有的相同行为
关键字 trait;只有方法签名,没有方法实现
pub trait Animal {// trait 的声明,一个trait中可以有多个方法
fn say(&self) -> String;
fn func1(&self){};
fn func2(&self){};
}
实现该Trait 的类型,必须提供具体的方法实现;
即 类型要和Trait进行关联;
例如:
pub struct Dog {
pub name : String,
pub age : i32,
}
impl Animal for Dog { //将该类型使用trait
fn say(&self) -> String {
format!("my name is {}",self.name)
}
}
其他类型也可以跟这个Trait进行关联
pub struct Cat {
pub name : String,
pub age : i32,
pub fun : String,
}
impl Animal for Cat {
fn say(&self) -> String {
format!("my name is {},my age is {}",self.name,self.age)
}
}
调用
let d1 = Dog{
name : "Tom".to_string(),
age : 3,
};
let c1 = Cat {
name : "Goj".to_string(),
age : 2,
fun : "xx".to_string(),
};
println!("{}",d1.say());
println!("{}",c1.say());
注意:
这个类型 或者 这个 trait是本地定义的;
无法为外部类型 实现外部trait
pub trait Animal {// trait 的声明,一个trait中可以有多个方法
fn say(&self) -> String;
fn hello(&self) { //默认实现的方法
println!("hello everyone!!");
}
fn goodbye(&self){
println!("{},goodbye !!",self.say()); //默认实现的方法可以调用其他方法,即使这个方法不是默认实现的方法
}
}
对于跟Trait关联的类型;可以对默认函数进行重新定义,即重构
impl Animal for Cat {
fn say(&self) -> String {
format!("my name is {},my age is {}",self.name,self.age)
}
fn hello(&self) { //在这个类型中,对默认方法进行了重构
println!("hello everyone ,i'm {}",self.name);
}
}
也可以不改变,使用默认方法
impl Animal for Dog { //将该类型使用trait
fn say(&self) -> String {
format!("my name is {}",self.name)
}
//在这个类型中,没有对trait的hello方法进行重构,所以使用的是默认的实现
}
期望这个函数的参数是有Animal trait功能的类型
pub fn speek(item : impl Animal) {
println!("this is me, {}",item.say());
}
speek(c1);
speek(d1);
直译就是Trait 约束,适用于比较复杂的场景
pub fn speek_v2<T: Animal>(item : T) {
println!("V2: {}",item.say());
}
//复杂场景
pub fn speek_v3<T:Animal>(item1 : T,item2 : T) {
println!("v3: {},{}",item1.say(),item2.say());
}
speek_v2(c1);
speek_v2(d1);
speek_v3(d1, d2);
期望这个函数的参数是同时支持两个trait功能的类型
使用 + 号,来表示同时支持多个trait
pub fn two_speek(item : impl Animal + Funcitons) {
println!("{}",item.say());
item.my_function();
}
trait bound
pub fn two_speek_v2<T:Animal + Funcitons>(item : T ) {
println!("{}",item.say());
item.my_function();
}
pub fn speek_v4<T : Animal,U : Animal + Funcitons>(item1 : T,item2 : U) {
item1.goodbye();
item2.my_function();
}
where 约束
pub fn speek_v5<T,U>(item1 : T,item2 : U)
where
T : Animal,
U : Animal + Funcitons,
{
item1.goodbye();
item2.my_function();
}
注意点,这个函数只能返回某一种具体的类型;返回可能得不同的类型,编译器会报错
pub fn create_animal(s : &str) -> impl Animal{
Dog {
name : String::from("s"),
age : 12,
}
}
定义一个泛型结构体
struct Pair<T> {
x : T,
y : T,
}
针对所有泛型T,定义一个方法:
impl<T> Pair<T> {
fn new(x :T ,y : T) -> Self {
Self {x , y}
} //这个泛型结构体有一个new 函数
}
针对满足要求的Trait类型,定义一个方法:
impl<T : Display + PartialOrd> Pair<T> {
// 这里对泛型结构体中的 cmp_display() 方法进行了约束,只有类型T 满足 Display 和 PartialOrd 两个Trait时,才能有这个方法。
fn cmp_display(&self) {
if self.x >= self.y {
println!("largest member is {}",self.x);
} else {
println!("largest member is {}",self.y);
}
}
}
满足某一约束条件然后去实现另一Trait 的行为叫覆盖约束
例如to_string()方法
3.to_string();
数字3 可以调用to_string()方法,
是由于 3 有 display方法,
所有有display方法的类型,都被实现了 to_string 方法