forked from inancgumus/learnrust
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lib.rs
284 lines (249 loc) · 8.46 KB
/
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
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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
//
// +-----------------+
// | MODULE |
// | +-------------+ |
// | | PACKAGE | |
// | | +---------+ | |
// | | | CRATE | | |
// | | +---------+ | |
// | +-------------+ |
// +-----------------+
//
// You can use modules to group related definitions together.
// So others can find what they're looking for more easily.
// That's why you should name your modules well.
// `mod` defines a new module named: `front_of_house`.
mod front_of_house {
// define another module named `hosting` within the front_of_house module.
//
// `pub` makes a definition public.
// -> Without `pub`, a definition is private by default.
// -> A parent can't learn details about its children.
// -> A child can learn everything about its parent.
pub mod hosting {
pub fn add_to_waitlist() {}
fn seat_at_table() {}
}
// define another module named `serving` within the front_of_house module.
mod serving {
fn take_order() {}
fn serve_order() {}
fn take_payment() {}
}
}
//
// The `module tree` of the front_of_house crate:
//
// crate <- module name
// └── front_of_house <- parent module
// ├── hosting <- a child of front_of_house
// │ ├──add_to_waitlist <- a child of hosting
// │ └──seat_at_table <- a sibling of add_to_waitlist
// └── serving <- a sibling of hosting
// ├── take_order <- ...
// ├── serve_order
// └── take_payment
//
// Looks like a directory structure, eh?
// Right.
// You can use modules to organize your code.
// Just like you can use directories to organize your files.
// note: eat_at_restaurant() is a sibling to the front_of_house module.
// -> they can see each other.
// -> that's why you can access front_of_house from this function.
pub fn eat_at_restaurant() {
// How to reach out to these modules?
// Absolute path (the recommended way)
crate::front_of_house::hosting::add_to_waitlist();
// Relative path
// This fn is also in the same crate.
// So you can skip typing `crate::`.
front_of_house::hosting::add_to_waitlist();
// If hosting and add_to_waitlist weren't `public` (marked with `pub`),
// Then we wouldn't be able to access them here.
}
// -------------------------------------------------------------------------------
// this fn is defined at the crate level (root).
fn serve_order() {}
// this module is also defined at the crate level (root).
mod back_of_house {
// this fn is defined at the back_of_house module level.
fn fix_incorrect_order() {
// it can call another sibling fn.
cook_order();
// normally, this one can't reach out to serve_order.
// because, they are at different levels.
//
// to reach it, this fn needs to use `super`:
//
// super -> the parent of back_of_house -> crate
//
super::serve_order();
}
// this fn is a sibling of fix_incorrect_order.
// it's been defined in the back_of_house module level.
fn cook_order() {}
// --------------------------------------------------------------------------
pub struct Breakfast {
// You can also declare fields as public.
pub toast: String,
// This one is private.
seasonal_fruit: String,
}
impl Breakfast {
// only with `summer()`, you can create Breakfast here.
// because: summer is an associated fn that can access to
// Breakfast internals.
// To a private field like: seasonal_fruit.
pub fn summer(toast: &str) -> Breakfast {
Breakfast {
toast: String::from(toast),
seasonal_fruit: String::from("peaches"),
}
}
// see: eat_meal() below.
}
// --------------------------------------------------------------------------
// When you can make an enum public, all of its variants become public.
// Enums aren't very useful unless their variants are public.
pub enum Appetizer {
Soup, // public
Salad, // public
}
// see: eat_appetizer() below.
}
// --------------------------------------------------------------------------
pub fn eat_meal() {
// Order a breakfast in the summer with Rye toast
let mut meal = back_of_house::Breakfast::summer("Rye");
// Change our mind about bread we'd like (toast is mutable & public)
meal.toast = String::from("Wheat");
println!("I'd like {} toast please", meal.toast);
// `seasonal_fruit` is private, we're not allowed to see or modify it.
// meal.seasonal_fruit = String::from("blueberries");
}
// this one can't create Breakfast because it cannot access the
// seasonal_fruit (private) field — unlike the summer fn above.
//
// pub fn cant_breakfast(toast: &str) -> back_of_house::Breakfast {
// back_of_house::Breakfast {
// toast: String::from(toast),
// seasonal_fruit: String::from("peaches"),
// }
// }
//
// Read more by running this command:
// rustc --explain E0063
// --------------------------------------------------------------------------
pub fn eat_appetizer() {
// Soup and Salad are public so you can access them here.
let order1 = back_of_house::Appetizer::Soup;
let order2 = back_of_house::Appetizer::Salad;
// ...
}
// --------------------------------------------------------------------------
pub fn eat_at_restaurant_verbose() {
//
// Using the fn like this is kind of cumbersome and repetitive:
//
crate::front_of_house::hosting::add_to_waitlist();
front_of_house::hosting::add_to_waitlist();
}
// There is a better way.
// Let's bring the hosting module to this scope.
use crate::front_of_house::hosting;
// ^ ^ ^
// | | |
// create module name child of
// name front_of_house module
pub fn eat_at_restaurant_concise() {
// And then you can call the definitions as if they're local:
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}
// --------------------------------------------------------------------------
//
// 😡UNIDIOMATIC:
//
// Don't bring a fn into scope with use.
//
// use crate::front_of_house::hosting::add_to_waitlist;
//
//
// 🥳 IDIOMATIC:
//
// Bringing the function's parent module into scope with use so
// so we have to specify the parent module when calling the function:
// -> makes it clear that the function isn't locally defined
// -> while still minimizing repetition of the full path.
//
// use crate::front_of_house::hosting;
//
// pub fn eat_at_restaurant_concise() {
// ★ It's clear that add_to_waitlist is an external fn.
// ★ And it belongs to the hosting module.
//
// hosting::add_to_waitlist();
// }
//
//
// However, it is 🥳 IDIOMATIC to bring structs, enums, and other items with use:
//
// This brings Hashmap struct into the scope.
//
// use std::collections::HashMap;
//
// fn main() {
// let mut map = HashMap::new();
// map.insert(1, 2);
// }
//
// If there is a clash, this is the 🥳 IDIOMATIC way:
//
// use std::fmt::Result; <- Result is still Result
// use std::io::Result as IoResult; <- Result becomes IoResult
//
// --------------------------------------------------------------------------
// RUST FACADE PATTERN: RE-EXPORTING
//
// Re-exporting is useful when the internal structure of your code
// is different from how programmers calling your code would think
// about the domain.
//
// mod front_of_house {
// pub mod hosting {
// pub fn add_to_waitlist() {}
// }
// }
// pub use crate::front_of_house::hosting;
//
// This way, external code can reach out to definitions like this:
//
// hosting::add_to_waitlist
//
// --------------------------------------------------------------------------
// 👉 `std`, the Standard Library crate is also external to any other packages.
// --------------------------------------------------------------------------
// NESTED `use` to clean up large `use` lists.
//
// 😡 Verbose:
//
// use std::cmp::Ordering;
// use std::io;
//
// 🥳 Concise:
//
// use std::{cmp::Ordering, io};
//
// You can use self to refer to the same package.
//
// 😡 Verbose:
//
// use std::io;
// use std::io::Write;
//
// 🥳 Concise:
//
// use std::io::{self, Write};
//