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/types/closure.md
+24-2
Original file line number
Diff line number
Diff line change
@@ -2,6 +2,7 @@
2
2
3
3
r[type.closure]
4
4
5
+
r[type.closure.intro]
5
6
A [closure expression] produces a closure value with a unique, anonymous type that cannot be written out.
6
7
A closure type is approximately equivalent to a struct which contains the captured values.
7
8
For instance, the following closure:
@@ -83,6 +84,7 @@ The mode is not affected by the code surrounding the closure, such as the lifeti
83
84
84
85
### `Copy` values
85
86
87
+
r[type.closure.capture.copy]
86
88
Values that implement [`Copy`] that are moved into the closure are captured with the `ImmBorrow` mode.
87
89
88
90
```rust
@@ -94,10 +96,13 @@ let c = || {
94
96
95
97
## Capture Precision
96
98
99
+
r[type.closure.capture.precision.capture-path]
97
100
A *capture path* is a sequence starting with a variable from the environment followed by zero or more place projections that were applied to that variable.
A *place projection* is a [field access], [tuple index], [dereference] (and automatic dereferences), or [array or slice index] expression applied to a variable.
100
104
105
+
r[type.closure.capture.precision.intro]
101
106
The closure borrows or moves the capture path, which may be truncated based on the rules described below.
102
107
103
108
For example:
@@ -124,6 +129,7 @@ This closure captures an immutable borrow of `s.f1.1`.
124
129
125
130
### Shared prefix
126
131
132
+
r[type.closure.capture.precision.shared-prefix]
127
133
In the case where a capture path and one of the ancestor’s of that path are both captured by a closure, the ancestor path is captured with the highest capture mode among the two captures, `CaptureMode = max(AncestorCaptureMode, DescendantCaptureMode)`, using the strict weak ordering:
Partial captures of arrays and slices are not supported; the entire slice or array is always captured even if used with wildcard pattern matching, indexing, or sub-slicing.
231
240
For example:
232
241
@@ -242,6 +251,7 @@ c();
242
251
println!("{:?}", x[1]); // ERROR: borrow of moved value: `x`
Because it is not allowed to move fields out of a reference, `move` closures will only capture the prefix of a capture path that runs up to, but not including, the first dereference of a reference.
261
272
The reference itself will be moved into the closure.
Because it is `unsafe` to dereference a raw pointer, closures will only capture the prefix of a capture path that runs up to, but not including, the first dereference of a raw pointer.
277
289
278
290
```rust
@@ -289,6 +301,7 @@ c();
289
301
290
302
### Union fields
291
303
304
+
r[type.closure.capture.precision.union]
292
305
Because it is `unsafe` to access a union field, closures will only capture the prefix of a capture path that runs up to the union itself.
293
306
294
307
```rust
@@ -314,6 +327,7 @@ c();
314
327
315
328
### Reference into unaligned `struct`s
316
329
330
+
r[type.closure.capture.precision.unaligned]
317
331
Because it is [undefined behavior] to create references to unaligned fields in a structure,
318
332
closures will only capture the prefix of the capture path that runs up to, but not including, the first field access into a structure that uses [the `packed` representation].
319
333
This includes all fields, even those that are aligned, to protect against compatibility concerns should any of the fields in the structure change in the future.
@@ -364,6 +378,7 @@ c();
364
378
365
379
### `Box` vs other `Deref` implementations
366
380
381
+
r[type.closure.capture.precision.box-deref]
367
382
The implementation of the [`Deref`] trait for [`Box`] is treated differently from other `Deref` implementations, as it is considered a special entity.
368
383
369
384
For example, let us look at examples involving `Rc` and `Box`. The `*rc` is desugared to a call to the trait method `deref` defined on `Rc`, but since `*box` is treated differently, it is possible to do a precise capture of the contents of the `Box`.
@@ -373,6 +388,7 @@ For example, let us look at examples involving `Rc` and `Box`. The `*rc` is desu
However, if the contents of the `Box` are moved into the closure, then the box is entirely captured. This is done so the amount of data that needs to be moved into the closure is minimized.
396
413
397
414
```rust
@@ -409,6 +426,7 @@ c_box();
409
426
410
427
#### `Box` with move closure
411
428
429
+
r[type.closure.capture.precision.box-move.read]
412
430
Similarly to moving contents of a `Box` in a non-`move` closure, reading the contents of a `Box` in a `move` closure will capture the `Box` entirely.
413
431
414
432
```rust
@@ -525,6 +543,7 @@ Because captures are often by reference, the following general rules arise:
525
543
526
544
## Drop Order
527
545
546
+
r[type.closure.drop-order]
528
547
If a closure captures a field of a composite types such as structs, tuples, and enums by value, the field's lifetime would now be tied to the closure. As a result, it is possible for disjoint fields of a composite types to be dropped at different times.
529
548
530
549
```rust
@@ -544,6 +563,7 @@ If a closure captures a field of a composite types such as structs, tuples, and
In Edition 2018 and before, closures always capture a variable in its entirety, without its precise capture path. This means that for the example used in the [Closure types](#closure-types) section, the generated closure type would instead look something like this:
Composite types such as structs, tuples, and enums are always captured in its entirety,
576
596
not by individual fields. As a result, it may be necessary to borrow into a local variable in order to capture a single field:
577
597
@@ -595,13 +615,15 @@ impl SetVec {
595
615
596
616
If, instead, the closure were to use `self.vec` directly, then it would attempt to capture `self` by mutable reference. But since `self.set` is already borrowed to iterate over, the code would not compile.
If the `move` keyword is used, then all captures are by move or, for `Copy` types, by copy, regardless of whether a borrow would work. The `move` keyword is usually used to allow the closure to outlive the captured values, such as if the closure is being returned or used to spawn a new thread.
Regardless of if the data will be read by the closure, i.e. in case of wild card patterns, if a variable defined outside the closure is mentioned within the closure the variable will be captured in its entirety.
As composite types are captured in their entirety, a closure which captures one of those composite types by value would drop the entire captured variable at the same time as the closure gets dropped.
0 commit comments