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
println!("{}", a.y); // Ok: Still use another field of the struct
53
+
// OK: 構造体の他のフィールドは、まだ使える
23
54
let c = || println!("{}", a.y); // Error: Tries to capture all of `a`
55
+
// エラー: `a` 全体をキャプチャしようとする
24
56
c();
25
57
```
26
58
59
+
<!--
27
60
Starting in Rust 2021, closures captures are more precise. Typically they will only capture the fields they use (in some cases, they might capture more than just what they use, see the Rust reference for full details). Therefore, the above example will compile fine in Rust 2021.
Disjoint capture was proposed as part of [RFC 2229](https://github.com/rust-lang/rfcs/blob/master/text/2229-capture-disjoint-fields.md) and the RFC contains details about the motivation.
As a part of the 2021 edition a migration lint, `rust_2021_incompatible_closure_captures`, has been added in order to aid in automatic migration of Rust 2018 codebases to Rust 2021.
The `let _ = x` statement here is a no-op, since the `_` pattern completely ignores the right-hand side, and `x` is a reference to a place in memory (in this case, a variable).
**Subtle:** There are other similar expressions, such as the "dummy lets" `let _ = &x` that we insert, which are not no-ops. This is because the right-hand side (`&x`) is not a reference to a place in memory, but rather an expression that must first be evaluated (and whose result is then discarded).
When a closure takes ownership of a value from a variable `t`, that value is then dropped when the closure is dropped, and not when the variable `t` goes out of scope:
@@ -94,10 +202,16 @@ When a closure takes ownership of a value from a variable `t`, that value is the
94
202
{
95
203
letc=||move_value(t); // t is moved here
96
204
} // c is dropped, which drops the tuple `t` as well
205
+
// c がドロップされ、そのときにタプル `t` もまたドロップされる
97
206
} // t goes out of scope here
207
+
// t はここでスコープを抜ける
98
208
```
99
209
210
+
<!--
100
211
The above code will run the same in both Rust 2018 and Rust 2021. However, in cases where the closure only takes ownership of _part_ of a variable, there can be differences:
@@ -108,44 +222,96 @@ The above code will run the same in both Rust 2018 and Rust 2021. However, in ca
108
222
letc=|| {
109
223
// In Rust 2018, captures all of `t`.
110
224
// In Rust 2021, captures only `t.0`
225
+
// Rust 2018 では、`t` 全体がキャプチャされる。
226
+
// Rust 2018 では、`t.0` だけがキャプチャされる
111
227
move_value(t.0);
112
228
};
113
229
114
230
// In Rust 2018, `c` (and `t`) are both dropped when we
115
231
// exit this block.
232
+
// Rust 2018 では、 `c` (と `t`) の両方が
233
+
// このブロックを抜けるときにドロップされる。
116
234
//
117
235
// In Rust 2021, `c` and `t.0` are both dropped when we
118
236
// exit this block.
237
+
// Rust 2021 では、 `c` と `t.0` の両方が
238
+
// このブロックを抜けるときにドロップされる。
119
239
}
120
240
121
241
// In Rust 2018, the value from `t` has been moved and is
122
242
// not dropped.
243
+
// Rust 2018 では、`t` はすでにムーブされており、ここではドロップされない
123
244
//
124
245
// In Rust 2021, the value from `t.0` has been moved, but `t.1`
125
246
// remains, so it will be dropped here.
247
+
// Rust 2021 では、`t.0` はムーブされているが、
248
+
// `t.1` は残っており、ここでドロップされる
126
249
}
127
250
```
128
251
252
+
<!--
129
253
In most cases, dropping values at different times just affects when memory is freed and is not important. However, some `Drop` impls (aka, destructors) have side-effects, and changing the drop order in those cases can alter the semantics of your program. In such cases, the compiler will suggest inserting a dummy `let` to force the entire variable to be captured.
In Rust 2021, since different values are being captured, this can affect what traits a closure will implement. The migration lints test each closure to see whether it would have implemented a given trait before and whether it still implements it now; if they find that a trait used to be implemented but no longer is, then "dummy lets" are inserted.
For instance, a common way to allow passing around raw pointers between threads is to wrap them in a struct and then implement `Send`/`Sync` auto trait for the wrapper. The closure that is passed to `thread::spawn` uses the specific fields within the wrapper but the entire wrapper is captured regardless. Since the wrapper is `Send`/`Sync`, the code is considered safe and therefore compiles successfully.
With disjoint captures, only the specific field mentioned in the closure gets captured, which wasn't originally `Send`/`Sync` defeating the purpose of the wrapper.
0 commit comments