Skip to content

Commit 4662059

Browse files
c410-f3rehuss
authored andcommitted
Add let_chains references
1 parent d43000c commit 4662059

File tree

2 files changed

+108
-62
lines changed

2 files changed

+108
-62
lines changed

Diff for: src/expressions/if-expr.md

+71-51
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
1-
# `if` and `if let` expressions
1+
# `if` expressions
22

3-
## `if` expressions
3+
## Syntax
4+
5+
The same syntax is used by `if`, `if let` and chains of expressions.
46

57
> **<sup>Syntax</sup>**\
68
> _IfExpression_ :\
7-
> &nbsp;&nbsp; `if` [_Expression_]<sub>_except struct expression_</sub> [_BlockExpression_]\
8-
> &nbsp;&nbsp; (`else` (
9-
> [_BlockExpression_]
10-
> | _IfExpression_
11-
> | _IfLetExpression_ ) )<sup>\?</sup>
9+
> &nbsp;&nbsp; `if` _IfLetList_ [_BlockExpression_]\
10+
> &nbsp;&nbsp; ( `else` _IfLetList_ [_BlockExpression_] )<sup>\?</sup>
11+
>
12+
> _IfLet_ :\
13+
> &nbsp;&nbsp; [_Expression_]<sub>_except struct expression_</sub>
14+
> | `let` [_Pattern_] `=` [_Expression_]<sub>_except struct expression_</sub>
15+
>
16+
> _IfLetList_ :\
17+
> &nbsp;&nbsp; _IfLet_ ( && _IfLet_ )*
18+
19+
## `if`
1220

1321
An `if` expression is a conditional branch in program control.
1422
The syntax of an `if` expression is a condition operand, followed by a consequent block, any number of `else if` conditions and blocks, and an optional trailing `else` block.
@@ -37,16 +45,7 @@ let y = if 12 * 15 > 150 {
3745
assert_eq!(y, "Bigger");
3846
```
3947

40-
## `if let` expressions
41-
42-
> **<sup>Syntax</sup>**\
43-
> _IfLetExpression_ :\
44-
> &nbsp;&nbsp; `if` `let` [_Pattern_] `=` [_Scrutinee_]<sub>_except lazy boolean operator expression_</sub>
45-
> [_BlockExpression_]\
46-
> &nbsp;&nbsp; (`else` (
47-
> [_BlockExpression_]
48-
> | _IfExpression_
49-
> | _IfLetExpression_ ) )<sup>\?</sup>
48+
## `if let`
5049

5150
An `if let` expression is semantically similar to an `if` expression but in place of a condition operand it expects the keyword `let` followed by a pattern, an `=` and a [scrutinee] operand.
5251
If the value of the scrutinee matches the pattern, the corresponding block will execute.
@@ -90,27 +89,6 @@ let a = if let Some(1) = x {
9089
assert_eq!(a, 3);
9190
```
9291

93-
An `if let` expression is equivalent to a [`match` expression] as follows:
94-
95-
<!-- ignore: expansion example -->
96-
```rust,ignore
97-
if let PATS = EXPR {
98-
/* body */
99-
} else {
100-
/*else */
101-
}
102-
```
103-
104-
is equivalent to
105-
106-
<!-- ignore: expansion example -->
107-
```rust,ignore
108-
match EXPR {
109-
PATS => { /* body */ },
110-
_ => { /* else */ }, // () if there is no else
111-
}
112-
```
113-
11492
Multiple patterns may be specified with the `|` operator. This has the same semantics as with `|` in `match` expressions:
11593

11694
```rust
@@ -126,30 +104,72 @@ if let E::X(n) | E::Y(n) = v {
126104
```
127105

128106
The expression cannot be a [lazy boolean operator expression][_LazyBooleanOperatorExpression_].
129-
Use of a lazy boolean operator is ambiguous with a planned feature change of the language (the implementation of if-let chains - see [eRFC 2947][_eRFCIfLetChain_]).
130-
When lazy boolean operator expression is desired, this can be achieved by using parenthesis as below:
107+
Scrutinee expressions also cannot be a [lazy boolean operator expression][_LazyBooleanOperatorExpression_] due to ambiguity and precedence with [chains of expressions][_ChainsOfExpressions_].
131108

132-
<!-- ignore: psuedo code -->
133-
```rust,ignore
134-
// Before...
135-
if let PAT = EXPR && EXPR { .. }
109+
## Chains of expressions
110+
111+
The following is an example of chaining multiple expressions, mixing `let` bindings and boolean expressions, and with expressions able to reference pattern bindings from previous expressions:
136112

137-
// After...
138-
if let PAT = ( EXPR && EXPR ) { .. }
113+
```rust
114+
fn single() {
115+
let outer_opt = Some(Some(1i32));
116+
117+
if let Some(inner_opt) = outer_opt
118+
&& let Some(number) = inner_opt
119+
&& number == 1
120+
{
121+
println!("Peek a boo");
122+
}
123+
}
124+
125+
The above is equivalent to the following without using expression chains:
126+
127+
fn nested() {
128+
let outer_opt = Some(Some(1i32));
129+
130+
if let Some(inner_opt) = outer_opt {
131+
if let Some(number) = inner_opt {
132+
if number == 1 {
133+
println!("Peek a boo");
134+
}
135+
}
136+
}
137+
}
138+
```
139+
140+
In other words, chains are equivalent to nested [`if let` expressions]:
141+
142+
<!-- ignore: expansion example -->
143+
```rust,ignore
144+
if let PAT0 = EXPR0 && let PAT1 = EXPR1 {
145+
/* body */
146+
} else {
147+
/* else */
148+
}
149+
```
139150

140-
// Before...
141-
if let PAT = EXPR || EXPR { .. }
151+
is equivalent to
142152

143-
// After...
144-
if let PAT = ( EXPR || EXPR ) { .. }
153+
<!-- ignore: expansion example -->
154+
```rust,ignore
155+
if let PAT0 = EXPR0 {
156+
if let PAT1 = EXPR1 {
157+
/* body */
158+
}
159+
else {
160+
/* else */
161+
}
162+
} else {
163+
/* else */
164+
}
145165
```
146166

147167
[_BlockExpression_]: block-expr.md
168+
[_ChainsOfExpressions_]: #chains-of-expressions
148169
[_Expression_]: ../expressions.md
149170
[_LazyBooleanOperatorExpression_]: operator-expr.md#lazy-boolean-operators
150171
[_Pattern_]: ../patterns.md
151172
[_Scrutinee_]: match-expr.md
152-
[_eRFCIfLetChain_]: https://github.com/rust-lang/rfcs/blob/master/text/2497-if-let-chains.md#rollout-plan-and-transitioning-to-rust-2018
153173
[`match` expression]: match-expr.md
154174
[boolean type]: ../types/boolean.md
155175
[scrutinee]: ../glossary.md#scrutinee

Diff for: src/expressions/loop-expr.md

+37-11
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,12 @@
55
> &nbsp;&nbsp; [_LoopLabel_]<sup>?</sup> (\
66
> &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; [_InfiniteLoopExpression_]\
77
> &nbsp;&nbsp; &nbsp;&nbsp; | [_PredicateLoopExpression_]\
8-
> &nbsp;&nbsp; &nbsp;&nbsp; | [_PredicatePatternLoopExpression_]\
98
> &nbsp;&nbsp; &nbsp;&nbsp; | [_IteratorLoopExpression_]\
109
> &nbsp;&nbsp; )
1110
1211
[_LoopLabel_]: #loop-labels
1312
[_InfiniteLoopExpression_]: #infinite-loops
1413
[_PredicateLoopExpression_]: #predicate-loops
15-
[_PredicatePatternLoopExpression_]: #predicate-pattern-loops
1614
[_IteratorLoopExpression_]: #iterator-loops
1715

1816
Rust supports four loop expressions:
@@ -39,9 +37,23 @@ A `loop` expression containing associated [`break` expression(s)](#break-express
3937

4038
## Predicate loops
4139

40+
### Syntax
41+
42+
The same syntax is used by `while`, `while let` and chains of expressions.
43+
4244
> **<sup>Syntax</sup>**\
43-
> _PredicateLoopExpression_ :\
44-
> &nbsp;&nbsp; `while` [_Expression_]<sub>_except struct expression_</sub> [_BlockExpression_]
45+
> [_PredicateLoopExpression_] :\
46+
> _WhileExpression_ :\
47+
> &nbsp;&nbsp; `while` _WhileLetList_ [_BlockExpression_]
48+
>
49+
> _WhileLet_ :\
50+
> &nbsp;&nbsp; ( [_Expression_]<sub>_except struct expression_</sub>
51+
> | `let` [_Pattern_] `=` [_Expression_]<sub>_except struct expression_</sub> )
52+
>
53+
> _WhileLetList_ :\
54+
> &nbsp;&nbsp; _WhileLet_ ( && _WhileLet_ )*
55+
56+
### `while`
4557

4658
A `while` loop begins by evaluating the [boolean] loop conditional operand.
4759
If the loop conditional operand evaluates to `true`, the loop body block executes, then control returns to the loop conditional operand.
@@ -58,13 +70,7 @@ while i < 10 {
5870
}
5971
```
6072

61-
## Predicate pattern loops
62-
63-
> **<sup>Syntax</sup>**\
64-
> [_PredicatePatternLoopExpression_] :\
65-
> &nbsp;&nbsp; `while` `let` [_Pattern_] `=` [_Scrutinee_]<sub>_except lazy boolean operator expression_</sub>
66-
> [_BlockExpression_]
67-
73+
### `while let`
6874

6975
A `while let` loop is semantically similar to a `while` loop but in place of a condition expression it expects the keyword `let` followed by a pattern, an `=`, a [scrutinee] expression and a block expression.
7076
If the value of the scrutinee matches the pattern, the loop body block executes then control returns to the pattern matching statement.
@@ -117,6 +123,26 @@ while let Some(v @ 1) | Some(v @ 2) = vals.pop() {
117123

118124
As is the case in [`if let` expressions], the scrutinee cannot be a [lazy boolean operator expression][_LazyBooleanOperatorExpression_].
119125

126+
### Chains of expressions
127+
128+
The following is an example of chaining multiple expressions, mixing `let` bindings and boolean expressions, and with expressions able to reference pattern bindings from previous expressions:
129+
130+
```rust
131+
fn main() {
132+
let outer_opt = Some(Some(1i32));
133+
134+
while let Some(inner_opt) = outer_opt
135+
&& let Some(number) = inner_opt
136+
&& number == 1
137+
{
138+
println!("Peek a boo");
139+
break;
140+
}
141+
}
142+
```
143+
144+
The only remark is the fact that parenthesis (`while (let Some(a) = opt && (let Some(b) = a)) && b == 1`) and `||` operators (`while let A(x) = e1 || let B(x) = e2`) are not currently supported.
145+
120146
## Iterator loops
121147

122148
> **<sup>Syntax</sup>**\

0 commit comments

Comments
 (0)