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
Copy file name to clipboardExpand all lines: src/ch18-00-patterns.md
+97-13Lines changed: 97 additions & 13 deletions
Original file line number
Diff line number
Diff line change
@@ -173,11 +173,50 @@ This will print `Current location: (3, 5)`.
173
173
174
174
### `while let`
175
175
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
+
letmutstack=Vec::new();
181
+
182
+
stack.push(1);
183
+
stack.push(2);
184
+
stack.push(3);
185
+
186
+
whileletSome(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.
177
195
178
196
### `for` loops
179
197
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
+
letv=vec![1, 2, 3];
205
+
206
+
for (index, value) inv {
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.
181
220
182
221
## Refutability: Whether a Pattern Might Fail to Match
183
222
@@ -291,8 +330,6 @@ more like destructuring?
291
330
292
331
### Named Variables and the Underscore Pattern
293
332
294
-
TODO: variable name always matches any value, underscore ignores everything, say the word "wildcard" somewhere about `_`
295
-
296
333
Usually, Rust will warn you if you create a variable but don't use it anywhere,
297
334
since that could be a bug. If you're prototyping or just starting a project,
298
335
though, you might create a variable that you'll use eventually, but temporarily
@@ -311,7 +348,8 @@ fn main() {
311
348
```
312
349
313
350
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:
315
353
316
354
```rust
317
355
fnfoo(_:i32) {
@@ -326,6 +364,32 @@ parameters like it would if we had given it a name.
326
364
327
365
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?
328
366
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
+
lets=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
+
329
393
### Multiple patterns
330
394
331
395
You can match multiple patterns with `|`:
@@ -430,7 +494,22 @@ fn main() {
430
494
}
431
495
```
432
496
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`.
434
513
435
514
We can mix, match, and nest destructuring patterns: we can do
436
515
something complicated like this example where we nest tuples inside of
@@ -485,21 +564,24 @@ match origin {
485
564
}
486
565
```
487
566
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:
489
568
490
569
```rust
491
570
fnmain() {
492
571
letnumbers= (2, 4, 8, 16, 32);
493
572
494
573
matchnumbers {
495
-
(first, .., fifth) => {
496
-
println!("Some numbers: {}, {}", first, fifth)
574
+
(first, .., last) => {
575
+
println!("Some numbers: {}, {}", first, last);
497
576
},
498
577
}
499
578
}
500
579
```
501
580
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:
503
585
504
586
```rust,ignore
505
587
fn main() {
@@ -513,7 +595,7 @@ fn main() {
513
595
}
514
596
```
515
597
516
-
error:
598
+
We get this error:
517
599
518
600
```text
519
601
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
523
605
| ^^
524
606
```
525
607
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
+
526
612
### Matching Ranges of Values with `...`
527
613
528
614
You can match a range of values with `...`:
@@ -553,8 +639,6 @@ This will print `early ASCII letter`.
0 commit comments