Rust进阶(2)-特征

特征

1. 概述

trait用于定义与其它类型共享的功能,类似于其它语言中的接口:

  1. 可以通过trait以抽象的方式定义共享的行为
  2. 可以使用trait bounds指定泛型是任何拥有特定行为的类型(前面泛型中提到过的,对泛型方法参数的约束:fn largest<T: PartialOrd + Copy>(list: &[T]))
  3. 默认实现:可以在定义trait的时候提供默认的行为,trait的类型可以使用默认的行为

2. 基本定义和实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//定义trait
pub trait GetInformation {
fn get_name(&self) -> &String;
fn get_age(&self) -> u32;
}

//trait默认实现
trait SchoolName{
fn get_school_name(&self) -> String{
String::from("HongXingSchool")
}
}

//实现trait
pub struct Student {
pub name: String,
pub age: u32,
}

impl SchoolName for Student{}

impl GetInformation for Student{
fn get_name(&self) -> &String{
&self.name
}
fn get_age(&self) -> u32{
self.age
}
}

pub struct Teacher{
pub name: String,
pub age: u32,
pub subject: String,
}

//重写默认实现
impl SchoolName for Teacher{
fn get_school_name(&self) -> String{
String::from("GuangMingSchool")
}
}

impl GetInformation for Teacher{
fn get_name(&self) -> &String{
&self.name
}
fn get_age(&self) -> u32{
self.age
}
}

// 方法中传入trait
fn print_information(item:impl GetInformation){
println!("name = {}",item.get_name());
println!("age = {}",item.get_age())
}

fn main() {
let s = Student{name:"xiaoming".to_string(),age:10};
let t = Teacher{name:"xiaohuang".to_string(),age:30,subject: String::from("math")};
println!("student,name = {},age = {}",s.get_name(),s.get_age());
println!("teacher,name = {},age = {}",t.get_name(),t.get_age());

// 方法中传入trait
/*print_information(s);
print_information(t);*/

let s_school_name = s.get_school_name();
let t_school_name = t.get_school_name();
println!("student school name = {}",s_school_name);
println!("teacher school name = {}",t_school_name);
}

3. trait作为方法参数(约束)

结合上面基本实现,将trait传入方法,其实就是强调传入的方法要实现指定的trait,用来约束

1
2
3
4
5
6
7
8
9
10
11
12
13
//trait作为方法参数
fn print_information(item:impl GetInformation){
println!("name = {}",item.get_name());
println!("age = {}",item.get_age())
}
fn main() {
let s = Student{name:"xiaoming".to_string(),age:10};
let t = Teacher{name:"xiaohuang".to_string(),age:30,subject: String::from("math")};

//trait作为方法参数
print_information(s);
print_information(t);
}

4. trait的默认实现

结合上面基本实现,使用默认实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//trait默认实现
trait SchoolName{
fn get_school_name(&self) -> String{
String::from("HongXingSchool")
}
}
impl SchoolName for Student{}

//重写默认实现
impl SchoolName for Teacher{
fn get_school_name(&self) -> String{
String::from("GuangMingSchool")
}
}

fn main() {
let s_school_name = s.get_school_name();
let t_school_name = t.get_school_name();
println!("student school name = {}",s_school_name);
println!("teacher school name = {}",t_school_name);
}

5. rait bounds

  1. 指定多个trait bound
  2. 返回trait类型

5.1 指定多个trait bound

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
trait GetName {
fn get_name(&self) -> &String;
}

trait GetAge {
fn get_age(&self) -> u32;
}

//方式一
fn print_information1<T: GetName + GetAge>(item: T) {
println!("name = {}", item.get_name());
println!("age = {}", item.get_age())
}

//方式二
fn print_information2<T>(item: T)
where T: GetName + GetAge {
println!("name = {}", item.get_name());
println!("age = {}", item.get_age())
}

//方式三,写法麻烦,不推荐
fn print_information3(item1: impl GetName, item2: impl GetAge) {
println!("name = {}", item1.get_name());
println!("age = {}", item2.get_age())
}

pub struct Student {
pub name: String,
pub age: u32,
}

impl GetName for Student {
fn get_name(&self) -> &String {
&self.name
}
}

impl GetAge for Student {
fn get_age(&self) -> u32 {
self.age
}
}

fn main() {
let s = Student { name: "xiaoming".to_string(), age: 10 };
print_information1(s);
print_information1(s);
print_information1(s);
}

5.2. 返回trait类型

//方法中仅可返回一种实现了trait的确定结构体类型,不能是根据条件返回不同的结构体类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
pub struct Student {
pub name: String,
pub age: u32,
}

//方法中仅可返回一种实现了trait的确定结构体类型,不能是根据条件返回不同的结构体类型
impl GetAge for Student {
fn get_age(&self) -> u32 {
self.age
}
}

fn produce_item_with_age() -> impl GetAge{
Student{
name:String::from("xiaoming"),
age:15,
}

//Student和Teacher,一个方法中,仅能出现一种返回类型
/*Teacher{
name:String::from("xiaohuang"),
age:30,
}*/
}

fn main() {
let s = produce_item_with_age();
}

5.3 使用trait bound有条件的实现方法

即,默认trait实现的方法中,约束了多个传入参数的条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
trait GetName {
fn get_name(&self) -> &String;
}

trait GetAge {
fn get_age(&self) -> u32;
}

struct PeopleMatchInformation<T, U> {
master: T,
student: U,
}

impl<T:GetName+GetAge,U:GetName+GetAge>PeopleMatchInformation<T,U>{
fn print_all_information(&self){
println!("master name={}",self.master.get_name());
println!("master age={}",self.master.get_age());
println!("student name={}",self.student.get_name());
println!("student age={}",self.student.get_age());
}
}

struct Teacher{
name:String,
age:u32,
}
impl GetName for Teacher{
fn get_name(&self) -> &String {
&(self.name)
}
}
impl GetAge for Teacher{
fn get_age(&self) -> u32 {
self.age
}
}

struct Student{
name:String,
age:u32,
}
impl GetName for Student{
fn get_name(&self) -> &String {
&(self.name)
}
}
impl GetAge for Student{
fn get_age(&self) -> u32 {
self.age
}
}
fn main() {
let s = Student{ name:"xiaoming".to_string(), age:15 };
let t = Teacher{name:"xiaohuang".to_string(),age:30};
let m = PeopleMatchInformation{master:t,student:s};
m.print_all_information();
}

5.4 对任何实现了特定trait的类型有条件的实现trait

说白了就是:一个结构体先实现了某个trait,才能实现另一个trait;
一个trait的实现,同时也就实现了另一个trait的方法,文字描述很难说清。具体看案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
trait GetName{
fn get_name(&self) -> &String;
}

trait PrintName{
fn print_name(&self);
}

impl<T:GetName> PrintName for T{
fn print_name(&self){
println!("name = {}",self.get_name())
}
}

struct Student{
name:String,
}
impl GetName for Student{
fn get_name(&self) -> &String {
&(self.name)
}
}

fn main() {
let s = Student{name:String::from("xiaohuang")};
s.print_name();
}

总结

本文编辑完毕

参考

[1] Rust 程序设计语言

  • Copyrights © 2017-2023 Jason
  • Visitors: | Views:

谢谢打赏~

微信