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,
58
+
The compiler prefers to capture a value by immutable borrow,
51
59
followed by unique immutable borrow (see below), by mutable borrow, and finally
52
-
by move. It will pick the first choice of these that is compatible with how the
53
-
captured variable is used inside the closure body. The compiler does not take
54
-
surrounding code into account, such as the lifetimes of involved variables, or
55
-
of the closure itself.
60
+
by move. It will pick the first choice of these that allows the closure to
61
+
compile. The choice is made only with regards to the contents of the closure
62
+
expression; the compiler does not take into account surrounding code, such as
63
+
the lifetimes of involved variables or fields.
64
+
>>>>>>> 881f305... Update closure types documentation so it includes information about RFC2229
56
65
57
-
If the `move` keyword is used, then all captures are by move or, for `Copy`
58
-
types, by copy, regardless of whether a borrow would work. The `move` keyword is
59
-
usually used to allow the closure to outlive the captured values, such as if the
60
-
closure is being returned or used to spawn a new thread.
66
+
## Capture Precision
67
+
68
+
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.
69
+
70
+
71
+
### Shared prefix
61
72
62
-
Composite types such as structs, tuples, and enums are always captured entirely,
63
-
not by individual fields. It may be necessary to borrow into a local variable in
64
-
order to capture a single field:
73
+
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.
78
+
79
+
```rust=
80
+
let s = String::new("S");
81
+
let t = (s, String::new("T"));
82
+
let mut u = (t, String::new("U"));
83
+
84
+
let c = || {
85
+
println!("{:?}", u); // u captured by ImmBorrow
86
+
u.0.truncate(0); // u.0 captured by MutBorrow
87
+
move_value(u.0.0); // u.0.0 captured by ByValue
88
+
};
89
+
```
90
+
91
+
Overall the closure will capture `u` by `ByValue`.
92
+
93
+
### Wild Card Patterns
94
+
Closures only capture data that needs to be read, which means the following closures will not capture `x`
65
95
66
96
```rust
67
-
# usestd::collections::HashSet;
68
-
#
69
-
structSetVec {
70
-
set:HashSet<u32>,
71
-
vec:Vec<u32>
72
-
}
97
+
letx=10;
98
+
letc=|| {
99
+
let_=x;
100
+
};
101
+
102
+
letc=||matchx {
103
+
_=>println!("Hello World!")
104
+
};
105
+
```
73
106
74
-
implSetVec {
75
-
fnpopulate(&mutself) {
76
-
letvec=&mutself.vec;
77
-
self.set.iter().for_each(|&n| {
78
-
vec.push(n);
79
-
})
80
-
}
81
-
}
107
+
### Capturing references in move contexts
108
+
109
+
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
85
-
to capture `self` by mutable reference. But since `self.set` is already
86
-
borrowed to iterate over, the code would not compile.
119
+
### Raw pointer dereference
120
+
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.
121
+
122
+
```rust,
123
+
struct T(String, String);
124
+
125
+
let t = T(String::from("foo"), String::from("bar"));
126
+
let t = &t as *const T;
127
+
128
+
let c = || unsafe {
129
+
println!("{}", (*t).0); // closure captures t
130
+
};
131
+
```
132
+
133
+
### Reference into unaligned `struct`s
134
+
135
+
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.
136
+
137
+
```rust
138
+
#[repr(packed)]
139
+
structT(String, String);
140
+
141
+
lett=T(String::from("foo"), String::from("bar"));
142
+
letc=||unsafe {
143
+
println!("{}", t.0); // closure captures t
144
+
};
145
+
```
146
+
147
+
148
+
### `Box` vs other `Deref` implementations
149
+
150
+
The compiler treats the implementation of the Deref trait for `Box` differently, as it is considered a special entity.
151
+
152
+
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`.
153
+
154
+
#### Non `move` closure
155
+
156
+
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.
175
+
176
+
```rust
177
+
structS(i32);
178
+
179
+
letb=Box::new(S(10));
180
+
letc_box=|| {
181
+
letx= (*b).0; // closure captures `b`
182
+
};
183
+
```
184
+
185
+
#### `move` closure
186
+
187
+
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.
188
+
189
+
```rust
190
+
structS(i32);
191
+
192
+
letb=Box::new(S(10));
193
+
letc_box=|| {
194
+
println!("{}", (*b).0); // closure captures `b`
195
+
};
196
+
```
87
197
88
198
## Unique immutable borrows in captures
89
199
@@ -113,6 +223,7 @@ the declaration of `y` will produce an error because it would violate the
113
223
uniqueness of the closure's borrow of `x`; the declaration of z is valid because
114
224
the closure's lifetime has expired at the end of the block, releasing the borrow.
115
225
226
+
116
227
## Call traits and coercions
117
228
118
229
Closure types all implement [`FnOnce`], indicating that they can be called once
@@ -156,12 +267,13 @@ following traits if allowed to do so by the types of the captures it stores:
156
267
157
268
The rules for [`Send`] and [`Sync`] match those for normal struct types, while
158
269
[`Clone`] and [`Copy`] behave as if [derived]. For [`Clone`], the order of
159
-
cloning of the captured variables is left unspecified.
270
+
cloning of the captured values is left unspecified.
271
+
160
272
161
273
Because captures are often by reference, the following general rules arise:
162
274
163
-
* A closure is [`Sync`] if all captured variables are [`Sync`].
164
-
* A closure is [`Send`] if all variables captured by non-unique immutable
275
+
* A closure is [`Sync`] if all captured values are [`Sync`].
276
+
* A closure is [`Send`] if all values captured by non-unique immutable
165
277
reference are [`Sync`], and all values captured by unique immutable or mutable
166
278
reference, copy, or move are [`Send`].
167
279
* A closure is [`Clone`] or [`Copy`] if it does not capture any values by
@@ -178,3 +290,98 @@ 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 ------------+ |
308
+
} // tuple.1 dropped here -----------------------------+
309
+
```
310
+
311
+
# Edition 2018 and before
312
+
313
+
## Closure types difference
314
+
315
+
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:
316
+
317
+
<!-- ignore: simplified -->
318
+
```rust,ignore
319
+
struct Closure<'a> {
320
+
rect : &'a mut Rectangle,
321
+
}
322
+
323
+
impl<'a> FnOnce<()> for Closure<'a> {
324
+
type Output = String;
325
+
fn call_once(self) -> String {
326
+
self.rect.left_top.x += 1;
327
+
self.rect.right_bottom.x += 1;
328
+
format!("{:?}", self.rect.left_top)
329
+
}
330
+
}
331
+
```
332
+
and the call to `f` would work as follows:
333
+
<!-- ignore: continuation of above -->
334
+
```rust,ignore
335
+
f(Closure { rect: rect });
336
+
```
337
+
338
+
## Capture precision difference
339
+
340
+
Composite types such as structs, tuples, and enums are always captured in its intirety,
341
+
not by individual fields. As a result, it may be necessary to borrow into a local variable in order to capture a single field:
342
+
343
+
```rust
344
+
# usestd::collections::HashSet;
345
+
#
346
+
structSetVec {
347
+
set:HashSet<u32>,
348
+
vec:Vec<u32>
349
+
}
350
+
351
+
implSetVec {
352
+
fnpopulate(&mutself) {
353
+
letvec=&mutself.vec;
354
+
self.set.iter().for_each(|&n| {
355
+
vec.push(n);
356
+
})
357
+
}
358
+
}
359
+
```
360
+
361
+
If, instead, the closure were to use `self.vec` directly, then it would attempt
362
+
to capture `self` by mutable reference. But since `self.set` is already
363
+
borrowed to iterate over, the code would not compile.
364
+
365
+
If the `move` keyword is used, then all captures are by move or, for `Copy`
366
+
types, by copy, regardless of whether a borrow would work. The `move` keyword is
367
+
usually used to allow the closure to outlive the captured values, such as if the
368
+
closure is being returned or used to spawn a new thread.
369
+
370
+
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.
371
+
372
+
## Drop order difference
373
+
374
+
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