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
23
56
let c = || println!("{}", a.y); // Error: Tries to capture all of `a`
24
57
c();
25
58
```
59
+
-->
26
60
61
+
```rust,ignore
62
+
let a = SomeStruct::new();
63
+
drop(a.x); // 構造体のフィールドの1つをムーブする
64
+
println!("{}", a.y); // OK: 構造体の他のフィールドは、まだ使える
65
+
let c = || println!("{}", a.y); // エラー: `a` 全体をキャプチャしようとする
66
+
c();
67
+
```
68
+
69
+
<!--
27
70
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:
@@ -96,9 +237,26 @@ When a closure takes ownership of a value from a variable `t`, that value is the
96
237
} // c is dropped, which drops the tuple `t` as well
97
238
} // t goes out of scope here
98
239
```
240
+
-->
99
241
242
+
```rust
243
+
# fnmove_value<T>(_:T){}
244
+
{
245
+
lett= (vec![0], vec![0]);
246
+
247
+
{
248
+
letc=||move_value(t); // t はここでムーブされる
249
+
} // c がドロップされ、そのときにタプル `t` もまたドロップされる
250
+
} // t はここでスコープを抜ける
251
+
```
252
+
253
+
<!--
100
254
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:
@@ -125,28 +283,99 @@ The above code will run the same in both Rust 2018 and Rust 2021. However, in ca
125
283
// remains, so it will be dropped here.
126
284
}
127
285
```
286
+
-->
128
287
288
+
```rust
289
+
# fnmove_value<T>(_:T){}
290
+
{
291
+
lett= (vec![0], vec![0]);
292
+
293
+
{
294
+
letc=|| {
295
+
// Rust 2018 では、`t` 全体がキャプチャされる。
296
+
// Rust 2018 では、`t.0` だけがキャプチャされる
297
+
move_value(t.0);
298
+
};
299
+
300
+
// Rust 2018 では、 `c` (と `t`) の両方が
301
+
// このブロックを抜けるときにドロップされる。
302
+
//
303
+
// Rust 2021 では、 `c` と `t.0` の両方が
304
+
// このブロックを抜けるときにドロップされる。
305
+
}
306
+
307
+
// Rust 2018 では、`t` はすでにムーブされており、ここではドロップされない
308
+
//
309
+
// Rust 2021 では、`t.0` はムーブされているが、
310
+
// `t.1` は残っており、ここでドロップされる
311
+
}
312
+
```
313
+
314
+
<!--
129
315
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