7.Rust的trait

trait可以暂时先翻译为“特征”,也可以不翻译吧,就叫trait。

1.trait的定义和实现
//定义trait
pub trait GetInfo {
    fn get_name(&self) -> &String;
    fn get_index(&self) -> i32;
}

//定义学生结构体
pub struct Student {
    pub name : String,
    pub index : i32,
    Is_Homework_completed : bool
}

pub struct Teacher {
    pub name : String,
    pub index : i32,
    pub sex : String
}

//实现trait
impl GetInfo for Student {
    fn get_name(&self) -> &String {
        &self.name
    }

    fn get_index(&self) -> i32 {
        self.index
    }
}

impl GetInfo for Teacher {
    fn get_name(&self) -> &String {
        &self.name
    }

    fn get_index(&self) -> i32 {
        self.index
    }
}

fn main() {
    let stu = Student { name: String::from("二狗"), index: 32 , Is_Homework_completed : false};
    println!("stu: {}, {}", stu.get_name(), stu.get_index());
    let t = Teacher { name: String::from("小芳"), index: 5 , sex : String::from("male")};
    println!("t: {}, {}", t.get_name(), t.get_index());
}

运行结果:

stu: 二狗, 32
t: 小芳, 5

在上面例子中,我们定义了一个trait,并分别为Student和Teacher实现了这个trait。

可是这个例子好像并不能体现trait的作用,我们本来就可以给结构体写这些函数呀。那么trait有什么用处呢?下面举一个例子。

2.trait应用举例
//定义trait
pub trait GetInfo {
    fn get_name(&self) -> &String;
    fn get_index(&self) -> i32;
}

//定义学生结构体
pub struct Student {
    pub name : String,
    pub index : i32,
    Is_Homework_completed : bool
}

pub struct Teacher {
    pub name : String,
    pub index : i32,
    pub sex : String
}

//实现trait
impl GetInfo for Student {
    fn get_name(&self) -> &String {
        &self.name
    }

    fn get_index(&self) -> i32 {
        self.index
    }
}

//此处我们把Teacher的实现注视掉
//impl GetInfo for Teacher {
//    fn get_name(&self) -> &String {
//        &self.name
//    }
//
//    fn get_index(&self) -> i32 {
//        self.index
//    }
//}

fn Print_info(item : impl GetInfo) {
    println!("name: {}", item.get_name());
    println!("index: {}", item.get_index());
}

fn main() {
    let stu = Student { name: String::from("二狗"), index: 32 , Is_Homework_completed : false};
    Print_info(stu);
}

运行结果:

name: 二狗
index: 32

此时trait的作用就体现出来了。Print_info函数要求:只有实现了GetInfo的数据结构才能调用Print_info函数。作为一种约束。

3.trait bound

上面是通过impl trait进行约束。

还可以通过trait bound来进行约束。

什么是trait bound呢,在上一期泛型中的介绍的

fn find_max (list : &[T]) -> T {
    let mut max = list[0];
    for &i in list.iter() {
        if i > max {
            max = i;
        }
    }
    max
}

这里的就是trait bound。我们看到,我们绑定了两个trait。那么如果通过impl方式,实现方式如下:

pub fn haha(item1: impl trait1, item2: impl trait2) {

这里的item1和item2是两个不同的类型,那么如果我需要是相同的类型呢,那就只能trait bound才能做到。

fn find_max (list : &[T]) -> T {
4.trait的默认实现

trait是可以有默认实现的。

举一个简单的例子:

//定义学生结构体
pub struct Student {
    pub name : String,
    pub index : i32,
    Is_Homework_completed : bool
}

pub struct Teacher {
    pub name : String,
    pub index : i32,
    pub sex : String
}

trait Print_school {
    fn print_shoolname(&self) {
        println!("你没有为这个类型实现这个trait!");
    }
}

impl Print_school for Student {
}

impl Print_school for Teacher {
    fn print_shoolname(&self) {
        println!("老师的学校是电子科大");
    }
}

fn main() {
    let stu = Student { name: String::from("二狗"), index: 32 , Is_Homework_completed : false};
    let tea = Teacher {name : "白质".to_string(), index : 8, sex : String::from("男")};
    stu.print_shoolname();
    tea.print_shoolname();
}

运行结果:

你没有为这个类型实现这个trait!
老师的学校是电子科大

这个例子应该是很好理解的。不需要解释吧。

5返回trait类型

这个先埋伏笔。以后在讲迭代器和闭包时如果我还能记得起的话,再举例讲解。

6.扩展方法

我们还可以通过trait为其他的类型添加成员方法,哪怕这个类型不是我们自己写的。

例如我们对i32添加一个方法:


trait Triple {
    fn triple(&self) -> i32;
}

impl Triple for i32 {
    fn triple(&self) -> i32 {
        *self * 3
    }
}

fn main() {
    let a = 10;
    println!("res: {}", a.triple());
}

运行结果:

res: 30

但是这并不是完全无条件的。Rust规定:impl块要么与trait的声明在同一个crate中,要么与类型的声明在同一个crate中。其实就是说,至少有一个在当前crate中。

7.Derive

前面我们在讲Copy和Clone时就看到过这个单词。

我们在impl某些trait时,其实是很机械化的。然而为很多类型重复单调的实现impl某些trait,非常滴不爽。因此,Rust提供了这个Derive,能够帮我们自动实现impl某些trait。

包括以下:

Debug Clone Copy Hash RustcEncodable RustcDecodable PartialEq Eq ParialOrd Ord Default FromPrimitive Send Sync

语法格式:

#[derive(Copy)]

后面我们可能会出一期,讲一讲常见的Derive应用场景。

欢迎关注微信公众号:Rust编程之路

你可能感兴趣的:(Rust编程入门系列)