forked from richardanaya/tour_of_rust
-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathchapter_4.yaml
281 lines (194 loc) · 18.6 KB
/
chapter_4.yaml
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
- title: Chapter 4 - Generic Types
content_markdown: >
Generic types are incredibly important in Rust. They are used in the
representation
of nullable values (i.e. variables which might not have a value yet), error
handling,
collections, and more! In this section we will be learning about the
foundational generic types
you will likely be using all the time.
- title: What Are Generic Types?
content_markdown: >
Generic types allow us to partially define a `struct` or `enum`, enabling a
compiler to create a fully
defined version at compile-time based off our code usage.
Rust generally can infer the final type by looking at our instantiation, but
if it needs help you
can always be explicit using the `::<T>` operator, also known by the name
`turbofish` (he's a good friend of mine!).
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&code=%2F%2F%20A%20partially%20defined%20struct%20type%0Astruct%20BagOfHolding%3CT%3E%20%7B%0A%20%20%20%20item%3A%20T%2C%0A%7D%0A%0Afn%20main()%20%7B%0A%20%20%20%20%2F%2F%20Note%3A%20by%20using%20generic%20types%20here%2C%20we%20create%20compile-time%20created%20types.%20%0A%20%20%20%20%2F%2F%20Turbofish%20lets%20us%20be%20explicit.%0A%20%20%20%20let%20i32_bag%20%3D%20BagOfHolding%3A%3A%3Ci32%3E%20%7B%20item%3A%2042%20%7D%3B%0A%20%20%20%20let%20bool_bag%20%3D%20BagOfHolding%3A%3A%3Cbool%3E%20%7B%20item%3A%20true%20%7D%3B%0A%20%20%20%20%0A%20%20%20%20%2F%2F%20Rust%20can%20infer%20types%20for%20generics%20too!%0A%20%20%20%20let%20float_bag%20%3D%20BagOfHolding%20%7B%20item%3A%203.14%20%7D%3B%0A%20%20%20%20%0A%20%20%20%20%2F%2F%20Note%3A%20never%20put%20a%20bag%20of%20holding%20in%20a%20bag%20of%20holding%20in%20real%20life%0A%20%20%20%20let%20bag_in_bag%20%3D%20BagOfHolding%20%7B%0A%20%20%20%20%20%20%20%20item%3A%20BagOfHolding%20%7B%20item%3A%20%22boom!%22%20%7D%2C%0A%20%20%20%20%7D%3B%0A%0A%20%20%20%20println!(%0A%20%20%20%20%20%20%20%20%22%7B%7D%20%7B%7D%20%7B%7D%20%7B%7D%22%2C%0A%20%20%20%20%20%20%20%20i32_bag.item%2C%20bool_bag.item%2C%20float_bag.item%2C%20bag_in_bag.item.item%0A%20%20%20%20)%3B%0A%7D%0A
- title: Representing Nothing
content_markdown: >
In other languages, the keyword `null` is used to represent an absence of a
value. It creates
difficulty in programming languages because it creates the possibility that
our program might fail
when interacting with a variable/field.
Rust does not have `null`, but it is not ignorant of the importance of
representing nothing!
Consider a naive representation using a tool we already know.
This pattern of providing a `None` alternative representation for one or
many alternate values is so
common in Rust because of its lack of a `null` value. Generic types help
solve this challenge.
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&code=enum%20Item%20%7B%0A%20%20%20%20Inventory(String)%2C%0A%20%20%20%20%2F%2F%20None%20represents%20the%20absence%20of%20an%20item%0A%20%20%20%20None%2C%0A%7D%0A%0Astruct%20BagOfHolding%20%7B%0A%20%20%20%20item%3A%20Item%2C%0A%7D%0A
- title: Option
content_markdown: >
Rust has a built in generic enum called `Option` that allows us to represent
nullable values
without using `null`.
```
enum Option<T> {
None,
Some(T),
}
```
This enum is so common, instances of the enum can be created anywhere with
the enum variants `Some` and `None`.
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&code=%2F%2F%20A%20partially%20defined%20struct%20type%0Astruct%20BagOfHolding%3CT%3E%20%7B%0A%20%20%20%20%2F%2F%20Our%20parameter%20type%20T%20can%20be%20handed%20to%20others%0A%20%20%20%20item%3A%20Option%3CT%3E%2C%0A%7D%0A%0Afn%20main()%20%7B%0A%20%20%20%20%2F%2F%20Note%3A%20A%20bag%20for%20i32%2C%20holding%20nothing!%20We%20have%20to%20specify%20the%20type%0A%20%20%20%20%2F%2F%20because%20otherwise%20Rust%20would%20not%20know%20what%20type%20of%20bag%20it%20is.%0A%20%20%20%20let%20i32_bag%20%3D%20BagOfHolding%3A%3A%3Ci32%3E%20%7B%20item%3A%20None%20%7D%3B%0A%0A%20%20%20%20if%20i32_bag.item.is_none()%20%7B%0A%20%20%20%20%20%20%20%20println!(%22there's%20nothing%20in%20the%20bag!%22)%0A%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20println!(%22there's%20something%20in%20the%20bag!%22)%0A%20%20%20%20%7D%0A%0A%20%20%20%20let%20i32_bag%20%3D%20BagOfHolding%3A%3A%3Ci32%3E%20%7B%20item%3A%20Some(42)%20%7D%3B%0A%0A%20%20%20%20if%20i32_bag.item.is_some()%20%7B%0A%20%20%20%20%20%20%20%20println!(%22there's%20something%20in%20the%20bag!%22)%0A%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20println!(%22there's%20nothing%20in%20the%20bag!%22)%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F%2F%20match%20lets%20us%20deconstruct%20Option%20elegantly%20and%20ensure%20we%20handle%20all%20cases!%0A%20%20%20%20match%20i32_bag.item%20%7B%0A%20%20%20%20%20%20%20%20Some(v)%20%3D%3E%20println!(%22found%20%7B%7D%20in%20bag!%22%2C%20v)%2C%0A%20%20%20%20%20%20%20%20None%20%3D%3E%20println!(%22found%20nothing%22)%2C%0A%20%20%20%20%7D%0A%7D%0A
- title: Result
content_markdown: >
Rust has a built in generic enum called `Result` that allows us to return a
value that has the possibility of failing.
It is the idiomatic way in which the language does error handling.
```
enum Result<T, E> {
Ok(T),
Err(E),
}
```
Note that our generics type has multiple *parameterized types* separated by
a comma.
This enum is so common, instances of the enum can be created anywhere with
the enum variants `Ok` and `Err`.
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&code=fn%20do_something_that_might_fail(i%3Ai32)%20-%3E%20Result%3Cf32%2CString%3E%20%7B%0A%20%20%20%20if%20i%20%3D%3D%2042%20%7B%0A%20%20%20%20%20%20%20%20Ok(13.0)%0A%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20Err(String%3A%3Afrom(%22this%20is%20not%20the%20right%20number%22))%20%20%20%0A%20%20%20%20%7D%0A%7D%0A%0Afn%20main()%20%7B%0A%20%20%20%20let%20result%20%3D%20do_something_that_might_fail(12)%3B%0A%0A%20%20%20%20%2F%2F%20match%20lets%20us%20deconstruct%20Result%20elegantly%20and%20ensure%20we%20handle%20all%20cases!%0A%20%20%20%20match%20result%20%7B%0A%20%20%20%20%20%20%20%20Ok(v)%20%3D%3E%20println!(%22found%20%7B%7D%22%2C%20v)%2C%0A%20%20%20%20%20%20%20%20Err(e)%20%3D%3E%20println!(%22Error%3A%20%7B%7D%22%2Ce)%2C%0A%20%20%20%20%7D%0A%7D%0A
- title: Failable Main
content_markdown: |
`main` has the capability of returning a `Result`!
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&code=fn%20do_something_that_might_fail(i%3A%20i32)%20-%3E%20Result%3Cf32%2C%20String%3E%20%7B%0A%20%20%20%20if%20i%20%3D%3D%2042%20%7B%0A%20%20%20%20%20%20%20%20Ok(13.0)%0A%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20Err(String%3A%3Afrom(%22this%20is%20not%20the%20right%20number%22))%0A%20%20%20%20%7D%0A%7D%0A%0A%2F%2F%20Main%20returns%20no%20value%2C%20but%20could%20return%20an%20error!%0Afn%20main()%20-%3E%20Result%3C()%2C%20String%3E%20%7B%0A%20%20%20%20let%20result%20%3D%20do_something_that_might_fail(12)%3B%0A%0A%20%20%20%20match%20result%20%7B%0A%20%20%20%20%20%20%20%20Ok(v)%20%3D%3E%20println!(%22found%20%7B%7D%22%2C%20v)%2C%0A%20%20%20%20%20%20%20%20Err(_e)%20%3D%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20handle%20this%20error%20gracefully%0A%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20return%20a%20new%20error%20from%20main%20that%20said%20what%20happened!%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20Err(String%3A%3Afrom(%22something%20went%20wrong%20in%20main!%22))%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F%2F%20Notice%20we%20use%20a%20unit%20value%20inside%20a%20Result%20Ok%0A%20%20%20%20%2F%2F%20to%20represent%20everything%20is%20fine%0A%20%20%20%20Ok(())%0A%7D%0A
- title: Graceful Error Handling
content_markdown: >
`Result` is so common that Rust has a powerful operator `?` for working with
them. These two statements are equivalent:
```
do_something_that_might_fail()?
```
```
match do_something_that_might_fail() {
Ok(v) => v,
Err(e) => return Err(e),
}
```
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&code=fn%20do_something_that_might_fail(i%3A%20i32)%20-%3E%20Result%3Cf32%2C%20String%3E%20%7B%0A%20%20%20%20if%20i%20%3D%3D%2042%20%7B%0A%20%20%20%20%20%20%20%20Ok(13.0)%0A%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20Err(String%3A%3Afrom(%22this%20is%20not%20the%20right%20number%22))%0A%20%20%20%20%7D%0A%7D%0A%0Afn%20main()%20-%3E%20Result%3C()%2C%20String%3E%20%7B%0A%20%20%20%20%2F%2F%20Look%20at%20how%20much%20code%20we%20saved!%0A%20%20%20%20let%20v%20%3D%20do_something_that_might_fail(42)%3F%3B%0A%20%20%20%20println!(%22found%20%7B%7D%22%2C%20v)%3B%0A%20%20%20%20Ok(())%0A%7D%0A
- title: Ugly Option/Result Handling
content_markdown: >
Working with `Option`/`Result` can be tedious when you are just trying to
write some quick code. Both `Option` and `Result` have a
function called `unwrap` that can be useful for getting a value in a quick
and dirty manner. `unwrap` will:
1. Get the value inside Option/Result
2. If the enum is of type None/Err, `panic!`
These two pieces of code are equivalent:
```
my_option.unwrap()
```
```
match my_option {
Some(v) => v,
None => panic!("some error message generated by Rust!"),
}
```
Similarly:
```
my_result.unwrap()
```
```
match my_result {
Ok(v) => v,
Err(e) => panic!("some error message generated by Rust!"),
}
```
Be a good rustacean and properly use `match` when you can!
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&code=fn%20do_something_that_might_fail(i%3A%20i32)%20-%3E%20Result%3Cf32%2C%20String%3E%20%7B%0A%20%20%20%20if%20i%20%3D%3D%2042%20%7B%0A%20%20%20%20%20%20%20%20Ok(13.0)%0A%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20Err(String%3A%3Afrom(%22this%20is%20not%20the%20right%20number%22))%0A%20%20%20%20%7D%0A%7D%0A%0Afn%20main()%20-%3E%20Result%3C()%2C%20String%3E%20%7B%0A%20%20%20%20%2F%2F%20concise%20but%20assumptive%20and%20gets%20ugly%20fast%0A%20%20%20%20let%20v%20%3D%20do_something_that_might_fail(42).unwrap()%3B%0A%20%20%20%20println!(%22found%20%7B%7D%22%2C%20v)%3B%0A%20%20%20%20%0A%20%20%20%20%2F%2F%20this%20will%20panic!%0A%20%20%20%20let%20v%20%3D%20do_something_that_might_fail(1).unwrap()%3B%0A%20%20%20%20println!(%22found%20%7B%7D%22%2C%20v)%3B%0A%20%20%20%20%0A%20%20%20%20Ok(())%0A%7D%0A
- title: if let
content_markdown: >
A much easier way to handle error propagation in Rust
is to use the `if let` block. It basically handles just
the only `match` branch that we are interested to get.
For instance, if we want to get the **error**,
`if let Err(..) = ..` will be used.
Otherwise, `if let Ok(..) = ..` will be chosen
to handle the **success** case.
`if let` can be used only for `Result` and `Option` data tyes.
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&code=fn+div%28x%3A+f64%2C+y%3A+f64%29+-%3E+Result%3Cf64%2C+String%3E+%7B%0A++++if+y+%3D%3D+0.0+%7B%0A++++++++return+Err%28String%3A%3Afrom%28%22Invalid+operation%3A+division+by+zero.%22%29%29%3B%0A++++%7D%0A++++return+Ok%28x+%2F+y%29%3B%0A%7D%0A%0A%0Afn+main%28%29+%7B%0A++++if+let+Ok%28res%29+%3D+div%2810.0%2C+1.0%29+%7B%0A++++++++println%21%28%22%7B%7D%22%2C+res%29%3B++++++++%2F%2F+will+be+displayed%0A++++%7D%0A++++%0A++++if+let+Err%28err%29+%3D+div%2810.0%2C+1.0%29+%7B%0A++++++++println%21%28%22%7B%7D%22%2C+err%29%3B++++++++%2F%2F+will+NOT+be+displayed%0A++++%7D%0A++++%0A%0A++++if+let+Ok%28res%29+%3D+div%2810.0%2C+0.0%29+%7B%0A++++++++println%21%28%22%7B%7D%22%2C+res%29%3B++++++++%2F%2F+will+be+displayed%0A++++%7D%0A++++if+let+Err%28err%29+%3D+div%2810.0%2C+0.0%29+%7B%0A++++++++println%21%28%22%7B%7D%22%2C+err%29%3B++++++++%2F%2F+will+NOT+be+displayed%0A++++%7D%0A%7D%0A
- title: Extracting a Result
content_markdown: >
Another brilliant way to extract a `Result<T, E> { Ok(T), Err(E), }`
is to use the functions `.ok()` and `.err()`, representing the specific variant.
These functions will return an `Option`:
- `Some` if the Result function had something to return, for results like `Result<i32, i32>`.
- `None` if the Result function returned either a `Err(())` or an `Ok(())`, for results like `Result<(), ()>`, `Result<i32, ()>` or `Result<(), i32>`
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&code=fn+div1%28x%3A+f64%2C+y%3A+f64%29+-%3E+Result%3Cf64%2C+String%3E+%7B%0A++++if+y+%3D%3D+0.0+%7B%0A++++++++return+Err%28String%3A%3Afrom%28%22Invalid+operation%3A+division+by+zero.%22%29%29%3B%0A++++%7D%0A++++return+Ok%28x+%2F+y%29%3B%0A%7D%0A%0A%0Afn+div2%28x%3A+f64%2C+y%3A+f64%29+-%3E+Result%3Cf64%2C+%28%29%3E+%7B%0A++++if+y+%3D%3D+0.0+%7B%0A++++++++%2F%2F+notice+that+the+error+returns+%60None%60%0A++++++++%2F%2F+therefore+will+be+pattern-matched+using+%60%28%29%60%0A++++++++return+Err%28%28%29%29%3B%0A++++%7D%0A++++return+Ok%28x+%2F+y%29%3B%0A%7D%0A%0Afn+main%28%29+%7B%0A++++let+good1+%3D+div1%2810.0%2C+1.0%29%3B%0A++++let+bad1+%3D+div1%2810.0%2C+0.0%29%3B%0A++++%0A++++%2F%2F+Using+.ok%28%29+will+extract+the+Ok+variant%0A++++%2F%2F+.ok%28%29+returns+an+Option%3A+Some%0A++++if+let+Some%28value%29+%3D+good1.ok%28%29+%7B%0A++++++++println%21%28%22Result+%28Ok%29%3A+%7B%7D%22%2C+value%29%3B%0A++++%7D+else+%7B%0A++++++++println%21%28%22Result+%28Err%29%22%29%3B%0A++++%7D%0A%0A++++%2F%2F+Using+.err%28%29+to+extract+the+Err+variant%0A++++%2F%2F+.err%28%29+returns+an+Option%3A+Some%0A++++if+let+Some%28err%29+%3D+bad1.err%28%29+%7B%0A++++++++println%21%28%22Error%3A+%7B%7D%22%2C+err%29%3B%0A++++%7D+else+%7B%0A++++++++println%21%28%22No+error+%28Ok%29%22%29%3B%0A++++%7D%0A++++%0A++++%0A++++let+good2+%3D+div2%2810.0%2C+1.0%29%3B%0A++++let+bad2+%3D+div2%2810.0%2C+0.0%29%3B%0A++++%0A++++%2F%2F+Using+.ok%28%29+will+extract+the+Ok+variant%0A++++%2F%2F+.ok%28%29+returns+an+Option%3A+Some%0A++++if+let+Some%28value%29+%3D+good2.ok%28%29+%7B%0A++++++++println%21%28%22Result+%28Ok%29%3A+%7B%7D%22%2C+value%29%3B%0A++++%7D+else+%7B%0A++++++++println%21%28%22Result+%28Err%29%22%29%3B%0A++++%7D%0A%0A++++%2F%2F+Using+.err%28%29+to+extract+the+Err+variant%0A++++%2F%2F+.err%28%29+returns+an+Option%3A+None%0A++++if+let+Some%28%28%29%29+%3D+bad2.err%28%29+%7B%0A++++++++println%21%28%22Error+occured%22%29%3B%0A++++%7D+else+%7B%0A++++++++println%21%28%22No+error+%28Ok%29%22%29%3B%0A++++%7D%0A%7D%0A
- title: About panic!
content_markdown: >
In Rust, `panic!` is a macro used to stop the execution of the program
without a recoverable error. When a panic occurs, the program immediately
stop, unwinding the stack and cleaning up resources along the way.
Moreover, the code instructions written after `panic!` will no longer be executed.
Usually, `panics` can by avoided by pattern matching the error with `Result`.
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=fn+main%28%29+%7B%0A++++println%21%28%22Reachable.%22%29%3B%0A%0A++++%2F%2F+Generates+a+panic%0A++++panic%21%28%22This+is+a+panic%21%22%29%3B%0A%0A++++%2F%2F+This+line+be+executed%0A++++println%21%28%22Unreachable%22%29%3B%0A%7D%0A
- title: Vectors
content_markdown: >
Some of the most useful generic types are collection types. A vector is a
variably sized list of items
represented by the struct `Vec`.
The macro `vec!` lets us easily create a vector rather than manually
constructing one.
`Vec` has the method `iter()` which creates an iterator from a vector,
allowing us to easily
put a vector into a `for` loop.
Memory Details:
* `Vec` is a struct, but internally it contains a reference to a fixed list
of its items on the heap.
* A vector starts with a default capacity; when more items are added than it
has capacity for, it
reallocates its data on the heap to have a new fixed list with large capacity.
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&code=fn%20main()%20%7B%0A%20%20%20%20%2F%2F%20We%20can%20be%20explicit%20with%20type%0A%20%20%20%20let%20mut%20i32_vec%20%3D%20Vec%3A%3A%3Ci32%3E%3A%3Anew()%3B%20%2F%2F%20turbofish%20%3C3%0A%20%20%20%20i32_vec.push(1)%3B%0A%20%20%20%20i32_vec.push(2)%3B%0A%20%20%20%20i32_vec.push(3)%3B%0A%0A%20%20%20%20%2F%2F%20But%20look%20how%20clever%20Rust%20is%20about%20determining%20the%20type%20automatically%0A%20%20%20%20let%20mut%20float_vec%20%3D%20Vec%3A%3Anew()%3B%0A%20%20%20%20float_vec.push(1.3)%3B%0A%20%20%20%20float_vec.push(2.3)%3B%0A%20%20%20%20float_vec.push(3.4)%3B%0A%0A%20%20%20%20%2F%2F%20That's%20a%20beautiful%20macro!%0A%20%20%20%20let%20string_vec%20%3D%20vec!%5BString%3A%3Afrom(%22Hello%22)%2C%20String%3A%3Afrom(%22World%22)%5D%3B%0A%0A%20%20%20%20for%20word%20in%20string_vec.iter()%20%7B%0A%20%20%20%20%20%20%20%20println!(%22%7B%7D%22%2C%20word)%3B%0A%20%20%20%20%7D%0A%7D%0A
- title: Iterators
content_markdown: >
In Rust, an iterator is an abstraction that decomposed a collection into a sequence of values.
You've seen an iterator before: in the `for` loop
```rust
// 0..5 iterates the values from 0 to 4
for i in 0..5 {
println!("{}", x);
}
```
If you are to modify each element of the collection,
iterators were designed with a very powerful function, `.map()`.
`.map()` and `.iter()` are methods provided by iterators and are commonly
used in working with collection (vectors and String, for instance).
The function `.iter()` iterates over a reference to each element of a collection,
generating a sequence of elements.
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&code=fn+main%28%29+%7B%0A++++let+numbers+%3D+vec%21%5B1%2C+2%2C+3%2C+4%2C+5%5D%3B%0A%0A++++%2F%2F+each+element+will+be+modified%0A++++let+doubled%3A+Vec%3Ci32%3E+%3D+numbers.into_iter%28%29.map%28%7Cx%7C+x+*+2%29.collect%28%29%3B%0A++++%0A++++%0A++++%2F%2F+generating+a+sequence+with+all+elements%0A++++for+%26el+in+doubled.iter%28%29+%7B%0A++++++++print%21%28%22%7B%7D+%22%2C+el%29%3B%0A++++%7D%0A++++println%21%28%29%3B%0A%7D%0A
- title: Chapter 4 - Conclusion
content_markdown: >
In one chapter we've learned how much power generic types give us! Don't
worry if you don't
know fully how to use everything, right now it's just good to be aware of
the major ideas you will
see again and again in code. Our functions are getting quite lengthy! In our
next chapter we will
spend talk about an important concept in Rust: data ownership.