工作空间的trait对象

  1. trait对象必须使用动态分发,通过其中的指针来知晓需要使用哪个方法,而trait 是静态分发
  2. trait对象使用Box dyn T来命名
  3. trait对象要求对象安全:
    只有对象安全的(object safe)的trait才可以组成trait对象,trait的方法满足以下两条
    要求才是对象安全的:
    (1) 返回值类型不为Self,如Clone就不是安全的,因为返回值是self
    (2) 方法没有任何泛型类型参数

例子

  • 创建工作空间
1
2
mkdir learn cd learn 
vim Cargo.toml
  • 设置工作空间
1
2
3
4
5
6
[workspace]
members = [
"gui",
"main",
]

  • 构建gui
1
2
3
# 在learn中
cargo new gui --lib
vim gui/src/lib.rs
  • 创建函数
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
pub trait Draw {
fn draw(&self);
}
pub struct Screen {
pub componets: Vec<Box<dyn Draw>>, //实现了Draw trait的对象,使用dyn关键字
}
//-------------

//泛型加trait bound不能使用,编译器处理方式为单态化,进行静态分发,已知道具体类型,
//T的类型不能变化,而我们是用的是SelectBox+Button类型
//而使用dyn时是使用动态类型,编译器不知道具体类型,而仅知道具体的指针大小

//pub struct Screen<T: Draw> {
// pub componets: Vec<T>,
// }
//impl<T> Screen<T>
//where T: Draw {
// pub fn run(&self) {
// for comp in self.componets.iter() {
// comp.draw();
// }
// }
// }
//---------------
impl Screen {
pub fn run(&self) {
for comp in self.componets.iter() {
comp.draw();
}
}
}
pub struct Button {
pub width: u32,
pub height: u32,
pub label: String,
}
impl draw for button {
fn draw(&self) {
println!("draw button,width = {},height = {},label = {}",self.width,self.height,,self.label);
}
}

pub struct SelectBox {
pub width: u32,
pub height: u32,
pub option: Vec<String>,
}

impl draw for SelectBox {
fn draw(&self) {
println!("draw SelectBox,width = {},height = {},option = {:?}",self.width,self.height,,self.option);
}
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2+2,4);
}
}
  • 创建main函数
1
2
3
4
# 位于learn
cargo new main
cd main
vim Cargo.toml
  • 添加依赖
1
2
[dependencies] 
gui = {path = "../gui"}
  • 主函数写法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//main/stc/main.rs
use gui::{Screen,SelectBox,Button};

fn main() {
let s = Screen {
componets: vec![
Box::new(Button {
width: 50,
height: 10,
label: String::from("ok"),
}),
Box::new(SelectBox {
width: 50,
height: 10,
option: vec![
String::from("yes"),
String::from("no"),
String::from("maybe"),
],
}),
],
};
s.run();
}

错误实例,返回self的trait

1
2
3
4
5
6
pub struct Sce {
pub com: Vec<Box<dyn Clone>>,
}
fn main() {
println!("hello world");
}