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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
use std::io;
use std::fmt::Debug;
pub fn enter(){
ch_05_01_enter();
ch_05_02_enter();
}
//rust定义结构体,和别的语言类似,使用struct关键字即可。
//比如下面这样的
struct User{
active:bool,
user_name:String,
email:String,
sign_in_count:u64,
}
fn ch_05_01_enter(){
//通过这样的方式来初始化并且声明一个struct
//类似于C#的模式匹配语法
let mut user = User{
active : false,
email : String::from("123@xxx.com"),
user_name:String::from("UserName"),
sign_in_count:1,
};
//使用域运算符"."来访问结构体中的某个成员
//注意要改变结构体中成员的值,要求它必须是可变的,Rust不允许仅将某个字段标记位可变
user.active = true;
user.email = String::from("456@xxx.com");
//使用实例创建方法生成并且获取一个结构体实例
let mut user_2 = gen_user(String::from("789@xxx.com"),String::from("user_name"));
//利用别的struct创建一个新的struct
let user_3 = User{
active:user_2.active,
email:user.email,
user_name:user_2.email,
sign_in_count:user.sign_in_count,
};
//但也可以使用“结构体更新语法”来实现上述目的,这样可以使得代码更简洁
//..语法制定了剩余未显式指定的字段均使用user_3的字段值
let user_4:User = User{
active:false,
..user_3
};
tuple_struct();
}
//另外也可以使用元组结构体,像下面这样
struct Color (i32,i32,i32);
struct Point(i32,i32,i32);
//这是没有任何字段的结构体,被称为类单元结构体,常被用于trait
struct AlwaysEqual;
//元组结构体没有字段名,只有类型
fn tuple_struct(){
let black:Color = Color(0,0,0);
let point:Point = Point(0,0,0);
//要访问元组结构体的成员,和普通元组一样
println!("black.color = {},{},{}",black.0,black.1,black.2);
//
}
//生成一个User实例的方法
fn gen_user(email:String , user_name:String)->User{
User{
active:true,
email:email,
user_name:user_name,
sign_in_count:0,
}
// let mut user = User{
// active:true,
// email:email,
// user_name:user_name,
// sign_in_count:0,
// };
// return user;
}
// use std::io;
//为了让结构体能够使用debug模式输出信息,使用derive属性来指定结构体使用Debug这种trait
// #[derive(PartialEq,Debug)]
#[derive(PartialEq)]
pub struct Rectangle{
width:u32,
height:u32,
}
impl Debug for Rectangle{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Rectangle")
.field("width", &self.width)
.field("height", &self.height)
.finish()
}
}
//在Rectangle结构体上定义area方法
//使用impl关键词 可以使impl块中的所有内容都与Rectangle类型关联
//这样的话就可以调用struct的area方法了
//在impl块中,self是impl块的别名,方法的第一个参数必须有一个名为self的Self类型参数
//所有在impl块中定义的方法都叫做关联方法,因为他们与impl后面的类型相关联
impl Rectangle{
pub fn new(width_:u32,height_:u32)->Self{
return Rectangle{
width:width_,
height:height_,
};
}
//计算自身面积
fn area(&self)->u32{
return self.width * self.height;
}
//计算自身是否能容纳另一个Rectangle
pub fn can_hold(&self,other:&Rectangle)->bool{
// return self.area() >= other.area();
return self.width >= other.width && self.height >= other.height;
}
fn can_hold_area(&self,other:&Rectangle)->bool{
return self.area() >= other.area();
}
//也可以定义第一个参数不为self的方法
//关键字Self指代impl后跟的类型
//使用::语法来调用这个关联方法,这表示,这个方法位于结构体的命名空间中,::用于关联方法和模块创建的命名空间
fn square(size:u32)->Self{
return Self {
width: size,
height: size
};
}
}
//每个结构体都允许拥有多个impl块
impl Rectangle{
fn print_self(&self){
println!("width:{},height:{}",self.width,self.height);
}
}
fn ch_05_02_enter(){
rectangles();
}
fn rectangles(){
let width:u32 = 50;
let height:u32 = 50;
// println!("the area is {}",area(width,height));
let rect : (u32,u32)= (30,30);
// println!("the area is {}",area_dimension(rect));
let rect_stct:Rectangle = Rectangle{
width:30,
height:30
};
//在不实现trait的情况下,以下代码是无法通过编译的
//这是因为,{}默认告诉println!使用被称为Display的格式,大部分的基本类型都实现了Display trait
//但对于自定义的结构体,需要自己去实现
// println!("the area is {}",area_struct(&rect_stct));
//{:?}代表Debug输出格式,它会将结构体内的值全都打印出来,这也是一种trait
//另外也可以使用{:#?}这种格式,它的打印信息将更加详细
//println!("the area is {:?}",rect_stct);
// println!("the area is {}",rect_stct.area());
let rect_test_1:Rectangle = Rectangle {
width:30,
height:30
};
let rect_test_2:Rectangle = Rectangle {
width:10,
height:40
};
let rect_test_3:Rectangle = Rectangle {
width:60,
height:54
};
// println!("can rect1 hold rect2? {}",rect_test_1.can_hold(&rect_test_2));
// println!("can rect1 hold rect3? {}",rect_test_1.can_hold_area(&rect_test_3));
let rect_squre:Rectangle = Rectangle::square(30);
print!("rect_square is {}",rect_squre.area());
}
fn area_struct(rect:&Rectangle)->u32{
rect.width * rect.height
}
//面积
fn area(width:u32,height:u32)->u32{
width * height
}
fn area_dimension(dimension:(u32,u32))->u32{
dimension.0*dimension.1
}