You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- Place the above multi-line string into `iterators/numbers.txt`.
60
62
- Replace the first `todo!` item with [reader.lines()](https://doc.rust-lang.org/stable/std/io/trait.BufRead.html#method.lines) and continue "chaining" the iterators until you've calculated the desired result.
61
63
- Run the code with `cargo run --bin iterators1` when inside the `exercise-templates` directory if you want a starting template.
62
64
@@ -100,6 +102,12 @@ The first point is not in vain - the original snippet has a bug in the upper bou
100
102
101
103
Think of iterators as lazy functions - they only carry out computation when a *consuming adapter* like `.collect()` is called, not the `.map()` itself.
102
104
105
+
### Iterator chains workflow advice
106
+
107
+
Start every iterator call on a new line, so that you can see closure arguments and type hints for the iterator at the end of the line clearly.
108
+
109
+
When in doubt, write `.map(|x| x)` first to see what item types you get and decide on what iterator methods to use and what to do inside a closure based on that.
110
+
103
111
### Turbo fish syntax `::<>`
104
112
105
113
Iterators sometimes struggle to figure out the types of all intermediate steps and need assistance.
This `::<SomeType>` syntax is called the [turbo fish operator](https://doc.rust-lang.org/book/appendix-02-operators.html?highlight=turbo%20fish#non-operator-symbols), and it disambiguates calling the same method with different output types, like `.parse::<i32>()` and `.parse::<f64>()` (try it!)
118
126
127
+
### Dealing with `.unwrap()`s in iterator chains
128
+
129
+
When starting out with iterators, it's very easy to be "led astray" by locally useful `.unwrap()`s as suggested by the compiler.
130
+
131
+
It's easy to get a slogging first solution with a lot of `Option` and `Result` wrapping and unwrapping that other languages wouldn't make explicit.
132
+
133
+
Concretely, the following snippet:
134
+
135
+
```rust
136
+
137
+
letnumeric_lines=reader.lines()
138
+
.map(|l|l.unwrap())
139
+
.map(|s|s.parse::<i32>())
140
+
.filter(|s|s.is_ok())
141
+
//...
142
+
143
+
```
144
+
145
+
can be replaced with a judicious use of [.filter_map()](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.filter_map):
146
+
147
+
```rust
148
+
letnumeric_lines=reader.lines()
149
+
.filter_map(|line|line.ok())
150
+
.filter_map(|s|s.parse().ok())
151
+
//...
152
+
```
153
+
154
+
You will relive similar experiences when learning Rust without knowing the right tools from the standard library that let you convert `Result` into what you actually need.
155
+
156
+
We make a special emphasis on avoiding "`.unwrap()` now, refactor later" because later usually never comes.
157
+
119
158
### Dereferences
120
159
121
160
Rust will often admonish you to add an extra dereference (`*`) by comparing the expected input and actual types, and you'll need to write something like `.map(|elem| *elem * 2)` to correct your code. A tell tale sign of this is that the expected types and the actual type differ by the number of `&`'s present.
@@ -136,47 +175,46 @@ let z = x.iter().zip(y.iter())
136
175
137
176
where the `.map(|(a, b)| a + b)` is iterating over `[(10, 1), (20, 2), (30, 3)]` and calling the left argument `a` and the right argument `b`, in each iteration.
138
177
139
-
## Iterator chains workflow advice
140
-
141
-
Start every iterator call on a new line, so that you can see closure arguments and type hints for the iterator at the end of the line clearly.
142
-
143
-
When in doubt, write `.map(|x| x)` first to see what item types you get and decide on what iterator methods to use and what to do inside a closure based on that.
144
-
145
178
## Step-by-Step-Solution
146
179
147
-
⚠️ NOTICE! ⚠️
148
-
149
-
When starting out with iterators, it's very easy to be "led astray" by doing what is locally useful as suggested by the compiler.
150
-
151
-
Concretely, our first solution will feel like a slog because we'll deal with a lot of `Option` and `Result` wrapping and unwrapping that other languages wouldn't make explicit.
152
-
153
-
A second more idiomatic solution will emerge in `Step 6` once we learn a few key idioms from the standard library.
154
-
155
-
You, unfortunately, relive similar experiences when learning Rust without knowing the right tools from the standard library to handle errors elegantly.
156
-
157
-
🧘 END OF NOTICE 🧘
158
-
159
180
In general, we also recommend using the Rust documentation to get unstuck. In particular, look for the examples in the [Iterator](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html) page of the standard library for this exercise.
160
181
161
182
If you ever feel completely stuck or that you haven’t understood something, please hail the trainers quickly.
162
183
163
184
### Step 1: New Project
164
185
165
-
Create a new binary Cargo project, check the build and see if it runs.
186
+
Create a new binary Cargo projectand run it.
166
187
167
188
Alternatively, use the [exercise-templates/iterators](../../exercise-templates/iterators/) template to get started.
168
189
<details>
169
190
<summary>Solution</summary>
170
191
171
192
```shell
172
193
cargo new iterators
173
-
cd iterators
194
+
cd iterators
174
195
cargo run
175
196
176
197
# if in exercise-book/exercise-templates/iterators
177
198
cargo run --bin iterators1
178
199
```
179
200
201
+
Place the string
202
+
203
+
```text
204
+
//ignore everything that is not a number
205
+
1
206
+
2
207
+
3
208
+
4
209
+
five
210
+
6
211
+
7
212
+
∞
213
+
9
214
+
X
215
+
```
216
+
217
+
and place it in `iterators/numbers.txt`.
180
218
</details>
181
219
182
220
### Step 2: Read the string data
@@ -188,6 +226,8 @@ Collect it into a string with `.collect::<String>()` and print it to verify you'
188
226
<details>
189
227
<summary>Solution</summary>
190
228
229
+
We'll get rid of the `.unwrap()` in the next section.
We'll collect into a `Vec<String>`s with [.parse()](https://doc.rust-lang.org/stable/std/primitive.str.html#method.parse) to show this intermediate step.
216
257
@@ -219,6 +260,8 @@ Note that you may or may not need type annotations on `.parse()` depending on if
219
260
<details>
220
261
<summary>Solution</summary>
221
262
263
+
If the use of `filter_map` here is unfamiliar, go back and reread the ``Dealing with .unwrap()s in iterator chains`` section.
0 commit comments