Skip to content

Commit c8f4aae

Browse files
committed
fix some TODOs
1 parent a7bcaf0 commit c8f4aae

File tree

1 file changed

+97
-13
lines changed

1 file changed

+97
-13
lines changed

src/ch18-00-patterns.md

Lines changed: 97 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,50 @@ This will print `Current location: (3, 5)`.
173173

174174
### `while let`
175175

176-
TODO: add a `while let` example
176+
A similar construction to `if let` is `while let`; this allows you to do
177+
a `while` loop while matching a pattern. For example:
178+
179+
```rust
180+
let mut stack = Vec::new();
181+
182+
stack.push(1);
183+
stack.push(2);
184+
stack.push(3);
185+
186+
while let Some(top) = stack.pop() {
187+
// Prints 3, 2, 1
188+
println!("{}", top);
189+
}
190+
```
191+
192+
Here, the `pop` method takes the last element out of the vector and returns `Some(value)`.
193+
If the vector is empty, it returns `None`. We can use `while let` to pop every element
194+
off this way.
177195

178196
### `for` loops
179197

180-
TODO: add a `for` loop example
198+
Looping with `for`, as we discussed in Chapter 3, is the most common loop construction in
199+
Rust code. But what we didn't talk about in that chapter was that `for` takes a pattern.
200+
For example, the `enumerate` method adapts an iterator to not only produce a value, but
201+
a tuple with the value and its index. We can use a pattern to destructure that tuple:
202+
203+
```rust
204+
let v = vec![1, 2, 3];
205+
206+
for (index, value) in v {
207+
println!("{} is at index {}", value, index);
208+
}
209+
```
210+
211+
This will print:
212+
213+
```text
214+
1 is at index 0
215+
2 is at index 1
216+
3 is at index 2
217+
```
218+
219+
The `(index, value)` construction there is a pattern.
181220

182221
## Refutability: Whether a Pattern Might Fail to Match
183222

@@ -291,8 +330,6 @@ more like destructuring?
291330

292331
### Named Variables and the Underscore Pattern
293332

294-
TODO: variable name always matches any value, underscore ignores everything, say the word "wildcard" somewhere about `_`
295-
296333
Usually, Rust will warn you if you create a variable but don't use it anywhere,
297334
since that could be a bug. If you're prototyping or just starting a project,
298335
though, you might create a variable that you'll use eventually, but temporarily
@@ -311,7 +348,8 @@ fn main() {
311348
```
312349

313350
Similarly with patterns as function parameters, if we didn't want to use the
314-
argument in the body of our function, we could use `_` for example:
351+
argument in the body of our function, we could use `_`, also known as a
352+
'wildcard' for example:
315353

316354
```rust
317355
fn foo(_: i32) {
@@ -326,6 +364,32 @@ parameters like it would if we had given it a name.
326364

327365
TODO: names starting with underscores behave the same as names not starting with underscores, aside from not getting an unused warning. Underscore is special; it drops right away. Example?
328366

367+
There's one more bit of subtlety here; `_x` and `_` have different behavior. That
368+
is, `_x` still binds to the variable of that name, but `_` doesn't bind at all.
369+
370+
For example, this will produce an error:
371+
372+
```rust,ignore
373+
let s = String::from("Hello!");
374+
375+
let _s = s;
376+
377+
println!("{}", s);
378+
```
379+
380+
Specifically, "use of moved value". When we assign `s` to `_s`, it moves, and so
381+
`s` is no longer valid. However...
382+
383+
```rust
384+
let s = String::from("Hello!");
385+
386+
let _ = s;
387+
388+
println!("{}", s);
389+
```
390+
391+
This works just fine. Becuase we never bind `s` to anything, it's not moved.
392+
329393
### Multiple patterns
330394

331395
You can match multiple patterns with `|`:
@@ -430,7 +494,22 @@ fn main() {
430494
}
431495
```
432496

433-
TODO: add enum destructuring example
497+
It's also common to use destructuring with `enums`. For example, the `is_none` method
498+
on `Option<T>` returns `true` if the `Option<T>` is `None`, and false if it is `Some`.
499+
Here's what it looks like:
500+
501+
```rust,ignore
502+
impl<T> Option<T> {
503+
pub fn is_some(&self) -> bool {
504+
match *self {
505+
Some(_) => true,
506+
None => false,
507+
}
508+
}
509+
}
510+
```
511+
512+
The `Some(_)` pattern will match any value, as long as it's `Some`.
434513

435514
We can mix, match, and nest destructuring patterns: we can do
436515
something complicated like this example where we nest tuples inside of
@@ -485,21 +564,24 @@ match origin {
485564
}
486565
```
487566

488-
TODO: explain this example with `..` in the middle that works:
567+
`..` will expand to as many values as it needs to be. For example:
489568

490569
```rust
491570
fn main() {
492571
let numbers = (2, 4, 8, 16, 32);
493572

494573
match numbers {
495-
(first, .., fifth) => {
496-
println!("Some numbers: {}, {}", first, fifth)
574+
(first, .., last) => {
575+
println!("Some numbers: {}, {}", first, last);
497576
},
498577
}
499578
}
500579
```
501580

502-
TODO: explain this example with `..` twice that doesn't work because it's ambiguous:
581+
Here, we have the first and last value matched, with `first` and `last`. The `..` will
582+
match all of the things in the middle.
583+
584+
This doesn't always work, though. Consider this:
503585

504586
```rust,ignore
505587
fn main() {
@@ -513,7 +595,7 @@ fn main() {
513595
}
514596
```
515597

516-
error:
598+
We get this error:
517599

518600
```text
519601
error: `..` can only be used once per tuple or tuple struct pattern
@@ -523,6 +605,10 @@ error: `..` can only be used once per tuple or tuple struct pattern
523605
| ^^
524606
```
525607

608+
It's not possible to determine that this is _actually_ the second value, like we gave
609+
the name. What if both `..` matched two elements? It'd be the third, value, not the second.
610+
Since this is ambiguous, Rust disallows it.
611+
526612
### Matching Ranges of Values with `...`
527613

528614
You can match a range of values with `...`:
@@ -553,8 +639,6 @@ This will print `early ASCII letter`.
553639

554640
### Extra Conditionals with Match Guards
555641

556-
TODO: is this really part of pattern syntax?
557-
558642
You can introduce *match guards* with `if`:
559643

560644
```rust

0 commit comments

Comments
 (0)