Skip to content

Commit 3d6c5e5

Browse files
authored
Merge pull request #516 from ehuss/if_while_or_patterns
Document if_while_or_patterns
2 parents 0e741fd + 72c1139 commit 3d6c5e5

File tree

3 files changed

+66
-30
lines changed

3 files changed

+66
-30
lines changed

src/expressions/if-expr.md

+22-6
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ assert_eq!(y, "Bigger");
4444

4545
> **<sup>Syntax</sup>**\
4646
> _IfLetExpression_ :\
47-
> &nbsp;&nbsp; `if` `let` [_Pattern_] `=` [_Expression_]<sub>_except struct or lazy boolean operator expression_</sub>
47+
> &nbsp;&nbsp; `if` `let` [_MatchArmPatterns_] `=` [_Expression_]<sub>_except struct or lazy boolean operator expression_</sub>
4848
> [_BlockExpression_]\
4949
> &nbsp;&nbsp; (`else` (
5050
> [_BlockExpression_]
@@ -95,10 +95,10 @@ let a = if let Some(1) = x {
9595
assert_eq!(a, 3);
9696
```
9797

98-
An `if let` expression is equivalent to a `match` expression as follows:
98+
An `if let` expression is equivalent to a [`match` expression] as follows:
9999

100100
```rust,ignore
101-
if let PAT = EXPR {
101+
if let PATS = EXPR {
102102
/* body */
103103
} else {
104104
/*else */
@@ -109,11 +109,26 @@ is equivalent to
109109

110110
```rust,ignore
111111
match EXPR {
112-
PAT => { /* body */ },
112+
PATS => { /* body */ },
113113
_ => { /* else */ }, // () if there is no else
114114
}
115115
```
116116

117+
Multiple patterns may be specified with the `|` operator. This has the same semantics
118+
as with `|` in `match` expressions:
119+
120+
```rust
121+
enum E {
122+
X(u8),
123+
Y(u8),
124+
Z(u8),
125+
}
126+
let v = E::Y(12);
127+
if let E::X(n) | E::Y(n) = v {
128+
assert_eq!(n, 12);
129+
}
130+
```
131+
117132
The expression cannot be a [lazy boolean operator expression][_LazyBooleanOperatorExpression_].
118133
Use of a lazy boolean operator is ambiguous with a planned feature change
119134
of the language (the implementation of if-let chains - see [eRFC 2947][_eRFCIfLetChain_]).
@@ -134,9 +149,10 @@ if let PAT = EXPR || EXPR { .. }
134149
if let PAT = ( EXPR || EXPR ) { .. }
135150
```
136151

137-
[_Expression_]: expressions.html
138152
[_BlockExpression_]: expressions/block-expr.html
139-
[_Pattern_]: patterns.html
153+
[_Expression_]: expressions.html
140154
[_LazyBooleanOperatorExpression_]: expressions/operator-expr.html#lazy-boolean-operators
155+
[_MatchArmPatterns_]: expressions/match-expr.html
141156
[_eRFCIfLetChain_]: https://github.com/rust-lang/rfcs/blob/master/text/2497-if-let-chains.md#rollout-plan-and-transitioning-to-rust-2018
157+
[`match` expression]: expressions/match-expr.html
142158
[scrutinee]: glossary.html#scrutinee

src/expressions/loop-expr.md

+21-11
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ while i < 10 {
6767

6868
> **<sup>Syntax</sup>**\
6969
> [_PredicatePatternLoopExpression_] :\
70-
> &nbsp;&nbsp; `while` `let` [_Pattern_] `=` [_Expression_]<sub>except struct expression</sub>
70+
> &nbsp;&nbsp; `while` `let` [_MatchArmPatterns_] `=` [_Expression_]<sub>except struct expression</sub>
7171
> [_BlockExpression_]
7272
7373
A `while let` loop is semantically similar to a `while` loop but in place of a
@@ -90,11 +90,11 @@ while let _ = 5 {
9090
}
9191
```
9292

93-
A `while let` loop is equivalent to a `loop` expression containing a `match`
94-
expression as follows.
93+
A `while let` loop is equivalent to a `loop` expression containing a [`match`
94+
expression] as follows.
9595

9696
```rust,ignore
97-
'label: while let PAT = EXPR {
97+
'label: while let PATS = EXPR {
9898
/* loop body */
9999
}
100100
```
@@ -104,12 +104,23 @@ is equivalent to
104104
```rust,ignore
105105
'label: loop {
106106
match EXPR {
107-
PAT => { /* loop body */ },
107+
PATS => { /* loop body */ },
108108
_ => break,
109109
}
110110
}
111111
```
112112

113+
Multiple patterns may be specified with the `|` operator. This has the same semantics
114+
as with `|` in `match` expressions:
115+
116+
```rust
117+
let mut vals = vec![2, 3, 1, 2, 2];
118+
while let Some(v @ 1) | Some(v @ 2) = vals.pop() {
119+
// Prints 2, 2, then 1
120+
println!("{}", v);
121+
}
122+
```
123+
113124
## Iterator loops
114125

115126
> **<sup>Syntax</sup>**\
@@ -272,12 +283,11 @@ and the `loop` must have a type compatible with each `break` expression.
272283
expression `()`.
273284

274285
[IDENTIFIER]: identifiers.html
275-
[temporary values]: expressions.html#temporary-lifetimes
276-
277-
[_Expression_]: expressions.html
286+
[LIFETIME_OR_LABEL]: tokens.html#lifetimes-and-loop-labels
278287
[_BlockExpression_]: expressions/block-expr.html
288+
[_Expression_]: expressions.html
289+
[_MatchArmPatterns_]: expressions/match-expr.html
279290
[_Pattern_]: patterns.html
280-
281-
[LIFETIME_OR_LABEL]: tokens.html#lifetimes-and-loop-labels
282-
291+
[`match` expression]: expressions/match-expr.html
283292
[scrutinee]: glossary.html#scrutinee
293+
[temporary values]: expressions.html#temporary-lifetimes

src/expressions/match-expr.md

+23-13
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ match x {
6262
Variables bound within the pattern are scoped to the match guard and the arm's
6363
expression. The [binding mode] (move, copy, or reference) depends on the pattern.
6464

65-
Multiple match patterns may be joined with the `|` operator:
65+
Multiple match patterns may be joined with the `|` operator. Each pattern will be
66+
tested in left-to-right sequence until a successful match is found.
6667

6768
```rust
6869
# let x = 9;
@@ -73,19 +74,30 @@ let message = match x {
7374
};
7475

7576
assert_eq!(message, "a few");
77+
78+
// Demonstration of pattern match order.
79+
struct S(i32, i32);
80+
81+
match S(1, 2) {
82+
S(z @ 1, _) | S(_, z @ 2) => assert_eq!(z, 1),
83+
_ => panic!(),
84+
}
7685
```
7786

78-
Please notice that the `2..=9` is a [Range Pattern], not a [Range Expression]
79-
and, thus, only those types of ranges supported by range patterns can be used
80-
in match arms.
87+
> Note: The `2..=9` is a [Range Pattern], not a [Range Expression]. Thus, only
88+
> those types of ranges supported by range patterns can be used in match arms.
89+
90+
Every binding in each `|` separated pattern must appear in all of the patterns
91+
in the arm. Every binding of the same name must have the same type, and have
92+
the same binding mode.
8193

8294
Match arms can accept _match guards_ to further refine the
8395
criteria for matching a case. Pattern guards appear after the pattern and
8496
consist of a bool-typed expression following the `if` keyword. A pattern guard
8597
may refer to the variables bound within the pattern they follow.
8698

8799
When the pattern matches successfully, the pattern guard expression is executed.
88-
If the expression is truthy, the pattern is successfully matched against.
100+
If the expression evaluates to true, the pattern is successfully matched against.
89101
Otherwise, the next pattern, including other matches with the `|` operator in
90102
the same arm, is tested.
91103

@@ -104,15 +116,13 @@ let message = match maybe_digit {
104116
> and side effects it has to execute multiple times. For example:
105117
>
106118
> ```rust
107-
> use std::cell::Cell;
108-
> fn main() {
109-
> let i : Cell<i32> = Cell::new(0);
110-
> match 1 {
111-
> 1 | _ if { i.set(i.get() + 1); false } => {}
112-
> _ => {}
113-
> }
114-
> assert_eq!(i.get(), 2);
119+
> # use std::cell::Cell;
120+
> let i : Cell<i32> = Cell::new(0);
121+
> match 1 {
122+
> 1 | _ if { i.set(i.get() + 1); false } => {}
123+
> _ => {}
115124
> }
125+
> assert_eq!(i.get(), 2);
116126
> ```
117127
118128
## Attributes on match arms

0 commit comments

Comments
 (0)