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/destructors.md
+44Lines changed: 44 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -415,6 +415,50 @@ let x = (&temp()).use_temp(); // ERROR
415
415
# x;
416
416
```
417
417
418
+
r[destructors.scope.temporary.if-let-guard]
419
+
### If Let Guards in Match Expressions
420
+
421
+
When an `if let` guard is evaluated in a match expression:
422
+
423
+
1.**Guard evaluation scope**: Variables bound by the `if let` pattern and any temporaries created during guard evaluation have a scope that extends through the match arm body if the guard succeeds.
424
+
425
+
2.**Failed guard cleanup**: If the `if let` guard fails to match:
426
+
- Any variables bound by the guard pattern are immediately dropped
427
+
- Temporaries created during guard evaluation are dropped
428
+
- Pattern matching continues to the next arm
429
+
430
+
3.**Successful guard**: If the guard succeeds:
431
+
- Guard-bound variables remain live for the duration of the match arm body
432
+
- They are dropped at the end of the match arm execution
433
+
434
+
4.**Multiple guards**: In arms with multiple guards connected by `&&`:
435
+
- Each failed guard drops its own bindings before evaluating the next guard
436
+
- Only successful guard bindings are available in the arm body
437
+
438
+
#### Example
439
+
440
+
```rust
441
+
# letvalue=Some(2)
442
+
# fnexpensive_operation(x:i32) ->Option<i32> {
443
+
# Some(x+2)
444
+
# }
445
+
#
446
+
matchvalue {
447
+
Some(x) ifletSome(y) =expensive_operation(x) => {
448
+
// Both x and y are live here
449
+
// expensive_operation(x) result is moved into y
450
+
// y dropped here at end of arm
451
+
} // Any temporaries from expensive_operation dropped here
452
+
Some(x) => {
453
+
// If first guard failed, y and expensive_operation result
454
+
// were already dropped before reaching this arm
455
+
}
456
+
None=> {}
457
+
}
458
+
```
459
+
460
+
This behavior is consistent across all Rust editions and matches the scoping semantics of nested `if let` expressions within match arms.
// Both `name` and `first_char` are available here
174
+
println!("Running: {} (starts with '{}')", name, first_char);
175
+
}
176
+
Command::Run(name) => {
177
+
println!("Cannot run command: {}", name);
178
+
}
179
+
_=> {}
172
180
}
173
181
```
174
-
Here, `guard_expr` is evaluated and matched against `subpattern`. If the `if let` expression in the guard matches successfully, the arm's body is executed. Otherwise, pattern matching continues to the next arm.
182
+
Here, the guard condition `let Some(first_char) = name.chars().next()` is evaluated. If the `if let` expression successfully matches (i.e., the string has at least one character), the arm's body is executed with both `name` and `first_char` available. Otherwise, pattern matching continues to the next arm.
183
+
184
+
The key point is that the `if let` guard creates a new binding (`first_char`) that's only available if the guard succeeds, and this binding can be used alongside the original pattern bindings (`name`) in the arm's body.
175
185
176
186
r[expr.match.if.let.guard.behavior]
177
187
When the pattern matches successfully, the `if let` expression in the guard is evaluated:
178
188
* The guard proceeds if the inner pattern (`subpattern`) matches the result of `guard_expr`.
179
189
* Otherwise, the next arm is tested.
180
190
181
-
```rust,ignore
182
-
let value = Some(10);
183
-
184
-
let msg = match value {
185
-
Some(x) if let Some(y) = Some(x - 1) => format!("Matched inner value: {}", y),
186
-
_ => "No match".to_string(),
187
-
};
188
-
```
189
-
190
-
r[expr.match.if.let.guard.scope]
191
-
* The `if let` guard may refer to variables bound by the outer match pattern.
192
-
* New variables bound inside the `if let` guard (e.g., `y` in the example above) are available within the body of the match arm where the guard evaluates to `true`, but are not accessible in other arms or outside the match expression.
193
-
194
-
```rust,ignore
195
-
let opt = Some(42);
196
-
197
-
match opt {
198
-
Some(x) if let Some(y) = Some(x + 1) => {
199
-
// Both `x` and `y` are available in this arm,
200
-
// since the pattern matched and the guard evaluated to true.
201
-
println!("x = {}, y = {}", x, y);
202
-
}
203
-
_ => {
204
-
// `y` is not available here --- it was only bound inside the guard above.
205
-
// Uncommenting the line below will cause a compile-time error:
206
-
// println!("{}", y); // error: cannot find value `y` in this scope
191
+
```rust
192
+
# letvalue=Some(2)
193
+
# fnprocess(x:i32) ->Result<i32, String> {
194
+
# Ok(x+2)
195
+
# }
196
+
#
197
+
matchvalue {
198
+
Some(x) ifletOk(y) =process(x) => {
199
+
// ^ ^
200
+
// | |
201
+
// | +-- `y` bound in if-let guard
202
+
// +-- `x` bound in match arm pattern
203
+
//
204
+
// Both `x` and `y` are available here
205
+
println!("Processed {} into {}", x, y);
207
206
}
207
+
_=> {}
208
208
}
209
-
210
-
// Outside the match expression, neither `x` nor `y` are in scope.
211
209
```
212
210
213
-
* The outer pattern variables (`x`) follow the same borrowing behavior as in standard match guards (see below).
214
-
215
-
r[expr.match.if.let.guard.drop]
216
-
217
-
* Variables bound inside `if let` guards are dropped before evaluating subsequent match arms.
218
-
219
-
* Temporaries created during guard evaluation follow standard drop semantics and are cleaned up appropriately.
211
+
r[expr.match.if.let.guard.scope]
220
212
221
-
r[expr.match.if.let.guard.borrowing]
222
-
Variables bound by the outer pattern follow the same borrowing rules as standard match guards:
223
-
* A shared reference is taken to pattern variables before guard evaluation
224
-
* Values are moved or copied only when the guard succeeds
225
-
* Moving from outer pattern variables within the guard is restricted
213
+
For detailed information about variable scope and drop behavior, see the [scope and drop section](../destructors.md#If-Let-Guards-in-Match-Expressions).
0 commit comments