Rust Trait

Rust 第16节 Trait

Trait 告诉编译器
某种类型具有那些并且可以与其他类型共享的功能
它的本质就是
不同类型具有的相同行为

声明一个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

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方法进行重构,所以使用的是默认的实现
}

Trait 作为参数

期望这个函数的参数是有Animal trait功能的类型

方法1 impl Trait 语法 使用于简单类型

pub fn speek(item : impl Animal) {
    println!("this is me, {}",item.say());
}
   speek(c1);
   speek(d1);

方法2 Trait bound 语法

直译就是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功能的类型
使用 + 号,来表示同时支持多个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();
}

当有更复杂场景时,使用where约束

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();
}

Trait 作为返回值

注意点,这个函数只能返回某一种具体的类型;返回可能得不同的类型,编译器会报错

pub fn create_animal(s : &str) -> impl Animal{
    Dog {
        name : String::from("s"),
        age : 12,
    }
}

泛型 加 Trait

定义一个泛型结构体

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 方法

你可能感兴趣的:(Rust,rust,java,开发语言)