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
The compiler prefers to capture a closed-over variable by immutable borrow,
63
+
The compiler prefers to capture a value by immutable borrow,
56
64
followed by unique immutable borrow (see below), by mutable borrow, and finally
57
-
by move. It will pick the first choice of these that is compatible with how the
58
-
captured variable is used inside the closure body. The compiler does not take
59
-
surrounding code into account, such as the lifetimes of involved variables, or
60
-
of the closure itself.
65
+
by move. It will pick the first choice of these that allows the closure to
66
+
compile. The choice is made only with regards to the contents of the closure
67
+
expression; the compiler does not take into account surrounding code, such as
68
+
the lifetimes of involved variables or fields.
69
+
>>>>>>> 881f305... Update closure types documentation so it includes information about RFC2229
61
70
62
-
r[type.closure.capture.move]
63
-
If the `move` keyword is used, then all captures are by move or, for `Copy`
64
-
types, by copy, regardless of whether a borrow would work. The `move` keyword is
65
-
usually used to allow the closure to outlive the captured values, such as if the
66
-
closure is being returned or used to spawn a new thread.
71
+
## Capture Precision
67
72
68
-
r[type.closure.capture.composite]
69
-
Composite types such as structs, tuples, and enums are always captured entirely,
70
-
not by individual fields. It may be necessary to borrow into a local variable in
71
-
order to capture a single field:
72
-
<!-- editor note, not true in Edition 2021 -->
73
+
The precise path that gets captured is typically the full path that is used in the closure, but there are cases where we will only capture a prefix of the path.
74
+
75
+
76
+
### Shared prefix
77
+
78
+
In the case where a 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
Note that this might need to be applied recursively.
83
+
84
+
```rust=
85
+
let s = String::new("S");
86
+
let t = (s, String::new("T"));
87
+
let mut u = (t, String::new("U"));
88
+
89
+
let c = || {
90
+
println!("{:?}", u); // u captured by ImmBorrow
91
+
u.0.truncate(0); // u.0 captured by MutBorrow
92
+
move_value(u.0.0); // u.0.0 captured by ByValue
93
+
};
94
+
```
95
+
96
+
Overall the closure will capture `u` by `ByValue`.
97
+
98
+
### Wild Card Patterns
99
+
Closures only capture data that needs to be read, which means the following closures will not capture `x`
73
100
74
101
```rust
75
-
# usestd::collections::HashSet;
76
-
#
77
-
structSetVec {
78
-
set:HashSet<u32>,
79
-
vec:Vec<u32>
80
-
}
102
+
letx=10;
103
+
letc=|| {
104
+
let_=x;
105
+
};
106
+
107
+
letc=||matchx {
108
+
_=>println!("Hello World!")
109
+
};
110
+
```
81
111
82
-
implSetVec {
83
-
fnpopulate(&mutself) {
84
-
letvec=&mutself.vec;
85
-
self.set.iter().for_each(|&n| {
86
-
vec.push(n);
87
-
})
88
-
}
89
-
}
112
+
### Capturing references in move contexts
113
+
114
+
Rust doesn't allow moving fields out of references. As a result, in the case of move closures, when values accessed through a shared references are moved into the closure body, the compiler, instead of moving the values out of the reference, would reborrow the data.
If, instead, the closure were to use `self.vec` directly, then it would attempt
93
-
to capture `self` by mutable reference. But since `self.set` is already
94
-
borrowed to iterate over, the code would not compile.
124
+
### Raw pointer dereference
125
+
In Rust, it's `unsafe` to dereference a raw pointer. Therefore, closures will only capture the prefix of a path that runs up to, but not including, the first dereference of a raw pointer.
126
+
127
+
```rust,
128
+
struct T(String, String);
129
+
130
+
let t = T(String::from("foo"), String::from("bar"));
131
+
let t = &t as *const T;
132
+
133
+
let c = || unsafe {
134
+
println!("{}", (*t).0); // closure captures t
135
+
};
136
+
```
137
+
138
+
### Reference into unaligned `struct`s
139
+
140
+
In Rust, it's `unsafe` to hold references to unaligned fields in a structure, and therefore, closures will only capture the prefix of the path that runs up to, but not including, the first field access into an unaligned structure.
141
+
142
+
```rust
143
+
#[repr(packed)]
144
+
structT(String, String);
145
+
146
+
lett=T(String::from("foo"), String::from("bar"));
147
+
letc=||unsafe {
148
+
println!("{}", t.0); // closure captures t
149
+
};
150
+
```
151
+
152
+
153
+
### `Box` vs other `Deref` implementations
154
+
155
+
The compiler treats the implementation of the Deref trait for `Box` differently, as it is considered a special entity.
156
+
157
+
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 by the compiler, the compiler is able to do precise capture on contents of the `Box`.
158
+
159
+
#### Non `move` closure
160
+
161
+
In a non `move` closure, if the contents of the `Box` are not moved into the closure body, the contents of the `Box` are precisely captured.
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.
180
+
181
+
```rust
182
+
structS(i32);
183
+
184
+
letb=Box::new(S(10));
185
+
letc_box=|| {
186
+
letx= (*b).0; // closure captures `b`
187
+
};
188
+
```
189
+
190
+
#### `move` closure
191
+
192
+
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.
193
+
194
+
```rust
195
+
structS(i32);
196
+
197
+
letb=Box::new(S(10));
198
+
letc_box=|| {
199
+
println!("{}", (*b).0); // closure captures `b`
200
+
};
201
+
```
95
202
96
203
## Unique immutable borrows in captures
97
204
@@ -123,6 +230,7 @@ the declaration of `y` will produce an error because it would violate the
123
230
uniqueness of the closure's borrow of `x`; the declaration of z is valid because
124
231
the closure's lifetime has expired at the end of the block, releasing the borrow.
125
232
233
+
126
234
## Call traits and coercions
127
235
128
236
r[type.closure.call]
@@ -176,12 +284,13 @@ following traits if allowed to do so by the types of the captures it stores:
176
284
r[type.closure.traits.behavior]
177
285
The rules for [`Send`] and [`Sync`] match those for normal struct types, while
178
286
[`Clone`] and [`Copy`] behave as if [derived]. For [`Clone`], the order of
179
-
cloning of the captured variables is left unspecified.
287
+
cloning of the captured values is left unspecified.
288
+
180
289
181
290
Because captures are often by reference, the following general rules arise:
182
291
183
-
* A closure is [`Sync`] if all captured variables are [`Sync`].
184
-
* A closure is [`Send`] if all variables captured by non-unique immutable
292
+
* A closure is [`Sync`] if all captured values are [`Sync`].
293
+
* A closure is [`Send`] if all values captured by non-unique immutable
185
294
reference are [`Sync`], and all values captured by unique immutable or mutable
186
295
reference, copy, or move are [`Send`].
187
296
* A closure is [`Clone`] or [`Copy`] if it does not capture any values by
@@ -195,3 +304,100 @@ Because captures are often by reference, the following general rules arise:
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.
} // 'c' and 'tuple.0' dropped here ------------+ |
322
+
} // tuple.1 dropped here -----------------------------+
323
+
```
324
+
325
+
# Edition 2018 and before
326
+
327
+
## Closure types difference
328
+
329
+
In Edition 2018 and before, a closure would capture variables in its entirety. This means that for the example used in the [Closure types](#closure-types) section, the generated closure type would instead look something like this:
330
+
331
+
<!-- ignore: simplified -->
332
+
```rust,ignore
333
+
struct Closure<'a> {
334
+
rect : &'a mut Rectangle,
335
+
}
336
+
337
+
impl<'a> FnOnce<()> for Closure<'a> {
338
+
type Output = String;
339
+
fn call_once(self) -> String {
340
+
self.rect.left_top.x += 1;
341
+
self.rect.right_bottom.x += 1;
342
+
format!("{:?}", self.rect.left_top)
343
+
}
344
+
}
345
+
```
346
+
and the call to `f` would work as follows:
347
+
<!-- ignore: continuation of above -->
348
+
```rust,ignore
349
+
f(Closure { rect: rect });
350
+
```
351
+
352
+
## Capture precision difference
353
+
354
+
r[type.closure.capture.composite]
355
+
Composite types such as structs, tuples, and enums are always captured in its intirety,
356
+
not by individual fields. As a result, it may be necessary to borrow into a local variable in order to capture a single field:
357
+
358
+
```rust
359
+
# usestd::collections::HashSet;
360
+
#
361
+
structSetVec {
362
+
set:HashSet<u32>,
363
+
vec:Vec<u32>
364
+
}
365
+
366
+
implSetVec {
367
+
fnpopulate(&mutself) {
368
+
letvec=&mutself.vec;
369
+
self.set.iter().for_each(|&n| {
370
+
vec.push(n);
371
+
})
372
+
}
373
+
}
374
+
```
375
+
376
+
If, instead, the closure were to use `self.vec` directly, then it would attempt
377
+
to capture `self` by mutable reference. But since `self.set` is already
378
+
borrowed to iterate over, the code would not compile.
379
+
380
+
r[type.closure.capture.move]
381
+
If the `move` keyword is used, then all captures are by move or, for `Copy`
382
+
types, by copy, regardless of whether a borrow would work. The `move` keyword is
383
+
usually used to allow the closure to outlive the captured values, such as if the
384
+
closure is being returned or used to spawn a new thread.
385
+
386
+
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.
387
+
388
+
## Drop order difference
389
+
390
+
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