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
<!-- TODO: The exception above isn't accurate, see https://github.com/rust-lang/reference/issues/569 -->
29
+
<!-- TODO: The struct exception above needs clarification, see https://github.com/rust-lang/reference/issues/1808
30
+
The chain grammar could use some work, see https://github.com/rust-lang/reference/issues/1811
31
+
-->
13
32
14
33
r[expr.if.intro]
15
-
An `if` expression is a conditional branch in program control.
16
-
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.
34
+
The syntax of an `if` expression is a sequence of one or more condition operands separated by `&&`,
35
+
followed by a consequent block, any number of `else if` conditions and blocks, and an optional trailing `else` block.
17
36
18
-
r[expr.if.condition-bool]
19
-
The condition operands must have the [boolean type].
37
+
r[expr.if.condition]
38
+
Condition operands must be either an [_Expression_] with a [boolean type] or a conditional `let` match.
20
39
21
40
r[expr.if.condition-true]
22
-
If a condition operand evaluates to `true`, the consequent block is executed and any subsequent `else if` or `else` block is skipped.
41
+
If all of the condition operands evaluate to `true` and all of the `let` patterns successfully match their [scrutinee]s,
42
+
the consequent block is executed and any subsequent `else if` or `else` block is skipped.
23
43
24
44
r[expr.if.else-if]
25
-
If a condition operand evaluates to `false`, the consequent block is skipped and any subsequent `else if` condition is evaluated.
45
+
If any condition operand evaluates to `false` or any `let` pattern does not match its scrutinee,
46
+
the consequent block is skipped and any subsequent `else if` condition is evaluated.
26
47
27
48
r[expr.if.else]
28
49
If all `if` and `else if` conditions evaluate to `false` then any `else` block is executed.
29
50
30
51
r[expr.if.result]
31
-
An if expression evaluates to the same value as the executed block, or `()` if no block is evaluated.
52
+
An `if` expression evaluates to the same value as the executed block, or `()` if no block is evaluated.
32
53
33
54
r[expr.if.type]
34
55
An `if` expression must have the same type in all situations.
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.
66
-
67
-
r[expr.if.let.pattern]
68
-
If the value of the scrutinee matches the pattern, the corresponding block will execute.
80
+
`let` patterns in an `if` condition allow binding new variables into scope when the pattern matches successfully.
69
81
70
-
r[expr.if.let.else]
71
-
Otherwise, flow proceeds to the following `else` block if it exists.
72
-
73
-
r[expr.if.let.result]
74
-
Like `if` expressions, `if let` expressions have a value determined by the block that is evaluated.
82
+
The following examples illustrate bindings using `let` patterns:
75
83
76
84
```rust
77
85
letdish= ("Ham", "Eggs");
78
86
79
-
//this body will be skipped because the pattern is refuted
87
+
//This body will be skipped because the pattern is refuted.
80
88
iflet ("Bacon", b) =dish {
81
89
println!("Bacon is served with {}", b);
82
90
} else {
83
91
// This block is evaluated instead.
84
92
println!("No bacon will be served");
85
93
}
86
94
87
-
//this body will execute
95
+
//This body will execute.
88
96
iflet ("Ham", b) =dish {
89
97
println!("Ham is served with {}", b);
90
98
}
@@ -94,47 +102,9 @@ if let _ = 5 {
94
102
}
95
103
```
96
104
97
-
r[expr.if.let.else-if]
98
-
`if` and `if let` expressions can be intermixed:
99
-
100
-
```rust
101
-
letx=Some(3);
102
-
leta=ifletSome(1) =x {
103
-
1
104
-
} elseifx==Some(2) {
105
-
2
106
-
} elseifletSome(y) =x {
107
-
y
108
-
} else {
109
-
-1
110
-
};
111
-
assert_eq!(a, 3);
112
-
```
113
-
114
-
r[expr.if.let.desugaring]
115
-
An `if let` expression is equivalent to a [`match` expression] as follows:
116
-
117
-
<!-- ignore: expansion example -->
118
-
```rust,ignore
119
-
if let PATS = EXPR {
120
-
/* body */
121
-
} else {
122
-
/*else */
123
-
}
124
-
```
125
-
126
-
is equivalent to
127
-
128
-
<!-- ignore: expansion example -->
129
-
```rust,ignore
130
-
match EXPR {
131
-
PATS => { /* body */ },
132
-
_ => { /* else */ }, // () if there is no else
133
-
}
134
-
```
135
-
136
105
r[expr.if.let.or-pattern]
137
-
Multiple patterns may be specified with the `|` operator. This has the same semantics as with `|` in `match` expressions:
106
+
Multiple patterns may be specified with the `|` operator.
107
+
This has the same semantics as with `|` in [`match` expressions]:
138
108
139
109
```rust
140
110
enumE {
@@ -148,27 +118,85 @@ if let E::X(n) | E::Y(n) = v {
148
118
}
149
119
```
150
120
151
-
r[expr.if.let.lazy-bool]
152
-
The expression cannot be a [lazy boolean operator expression][expr.bool-logic].
153
-
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_]).
154
-
When lazy boolean operator expression is desired, this can be achieved by using parenthesis as below:
121
+
r[expr.if.chains]
122
+
## Chains of conditions
155
123
156
-
<!-- ignore: pseudo code -->
157
-
```rust,ignore
158
-
// Before...
159
-
if let PAT = EXPR && EXPR { .. }
124
+
r[expr.if.chains.intro]
125
+
Multiple condition operands can be separated with `&&`.
160
126
161
-
// After...
162
-
if let PAT = ( EXPR && EXPR ) { .. }
127
+
r[expr.if.chains.order]
128
+
Similar to a `&&`[_LazyBooleanOperatorExpression_], each operand is evaluated from left-to-right until an operand evaluates as `false` or a `let` match fails,
129
+
in which case the subsequent operands are not evaluated.
163
130
164
-
// Before...
165
-
if let PAT = EXPR || EXPR { .. }
131
+
r[expr.if.chains.bindings]
132
+
The bindings of each pattern are put into scope to be available for the next condition operand and the consequent block.
166
133
167
-
// After...
168
-
if let PAT = ( EXPR || EXPR ) { .. }
134
+
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:
The above is equivalent to the following without using chains of conditions:
150
+
151
+
```rust
152
+
fnnested() {
153
+
letouter_opt=Some(Some(1i32));
154
+
155
+
ifletSome(inner_opt) =outer_opt {
156
+
ifletSome(number) =inner_opt {
157
+
ifnumber==1 {
158
+
println!("Peek a boo");
159
+
}
160
+
}
161
+
}
162
+
}
163
+
```
164
+
165
+
r[expr.if.chains.or]
166
+
If any condition operand is a `let` pattern, then none of the condition operands can be a `||`[lazy boolean operator expression][_LazyBooleanOperatorExpression_] due to ambiguity and precedence with the `let` scrutinee.
167
+
If a `||` expression is needed, then parentheses can be used. For example:
0 commit comments