Skip to content

Commit 18d5952

Browse files
「クロージャはフィールドごとにキャプチャする」を翻訳
1 parent 3165cc7 commit 18d5952

File tree

2 files changed

+251
-1
lines changed

2 files changed

+251
-1
lines changed

TranslationTable.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
| diverging | 発散する〜(上の diverge を修飾語として使った場合)
7171
| documentation comment | ドキュメンテーションコメント
7272
| documentation test | ドキュメンテーションテスト
73+
| drop | ドロップ
7374
| early return | 早期リターン
7475
| edition | エディション
7576
| empty tuple | 空タプル
@@ -130,10 +131,12 @@
130131
| memory | メモリ
131132
| method | メソッド
132133
| monomorphization | 単相化
133-
| move | ムーブ
134+
| move | ムーブ(する)
135+
| move out | ムーブする、ムーブアウトする
134136
| mutability | ミュータビリティ
135137
| mutable | ミュータブル
136138
| mutable binding | ミュータブルな束縛
139+
| mutate | 変更する、書き換える
137140
| mutual-exclusion | 相互排他
138141
| null | ヌル
139142
| object-safe | オブジェクト安全

src/rust-2021/disjoint-capture-in-closures.md

Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,136 @@
1+
<!--
12
# Disjoint capture in closures
3+
-->
24

5+
# クロージャはフィールドごとにキャプチャする
6+
<!-- 代案: クロージャのフィールドごとのキャプチャ -->
7+
<!-- 代案: クロージャの非交差キャプチャ -->
8+
<!-- 代案: クロージャの素(集合)キャプチャ -->
9+
10+
<!--
311
## Summary
12+
-->
13+
14+
## 概要
415

16+
<!--
517
- `|| a.x + 1` now captures only `a.x` instead of `a`.
618
- This can cause things to be dropped at different times or affect whether closures implement traits like `Send` or `Clone`.
719
- If possible changes are detected, `cargo fix` will insert statements like `let _ = &a` to force a closure to capture the entire variable.
20+
-->
821

22+
- `|| a.x + 1``a` でなく `a.x` だけをキャプチャするようになりました。
23+
- これにより、ドロップのタイミングが変わったり、クロージャが `Send``Clone` を実装するかどうかが変わったりします。
24+
- `cargo fix` は、可能だと判断したときに、 `let _ = &a` のような文を挿入して、クロージャが変数全体をキャプチャするように強制します。
25+
26+
<!--
927
## Details
28+
-->
29+
30+
## 詳細
1031

32+
<!--
1133
[Closures](https://doc.rust-lang.org/book/ch13-01-closures.html)
1234
automatically capture anything that you refer to from within their body.
1335
For example, `|| a + 1` automatically captures a reference to `a` from the surrounding context.
36+
-->
1437

38+
[クロージャ](https://doc.rust-lang.org/book/ch13-01-closures.html)は、本体の中で使用しているすべてのものを自動的にキャプチャします。<!--TODO: 日本語版の TRPL に置き換える? -->
39+
例えば、`|| a + 1` と書くと、周囲のコンテキスト中の `a` への参照が自動的にキャプチャされます。
40+
41+
<!--
1542
In Rust 2018 and before, closures capture entire variables, even if the closure only uses one field.
1643
For example, `|| a.x + 1` captures a reference to `a` and not just `a.x`.
1744
Capturing `a` in its entirety prevents mutation or moves from other fields of `a`, so that code like this does not compile:
45+
-->
46+
47+
Rust 2018 以前では、クロージャに使われているのが1つのフィールドだけであっても、クロージャは変数全体をキャプチャします。
48+
例えば、 `|| a.x + 1``a.x` への参照だけでなく、`a` への参照をキャプチャします。
49+
`a` 全体がキャプチャされると、`a` の他のフィールドの値を書き換えたりムーブしたりできなくなります。従って以下のようなコードはコンパイルに失敗します:
1850

51+
<!--
1952
```rust,ignore
2053
let a = SomeStruct::new();
2154
drop(a.x); // Move out of one field of the struct
2255
println!("{}", a.y); // Ok: Still use another field of the struct
2356
let c = || println!("{}", a.y); // Error: Tries to capture all of `a`
2457
c();
2558
```
59+
-->
2660

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+
<!--
2770
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.
71+
-->
72+
73+
Rust 2021 からは、クロージャのキャプチャはより精密になります。 特に、使用されるフィールドだけがキャプチャされるようになります
74+
(場合によっては、使用する変数以外にもキャプチャすることもあり得ます。詳細に関しては Rust リファレンスを参照してください)。
75+
したがって、上記のコードは Rust 2021 では問題ありません。
2876

77+
<!--
2978
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.
79+
-->
80+
81+
フィールドごとのキャプチャは [RFC 2229](https://github.com/rust-lang/rfcs/blob/master/text/2229-capture-disjoint-fields.md) の一部として提案されました。この RFC にはより詳しい動機が記載されています。
3082

83+
<!--
3184
## Migration
85+
-->
3286

87+
## 移行
88+
89+
<!--
3390
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.
91+
-->
92+
93+
Rust 2018 から Rust 2021 への自動移行の支援のため、2021 エディションには、移行用のリント`rust_2021_incompatible_closure_captures` が追加されています。
3494

95+
<!--
3596
In order to have `rustfix` migrate your code to be Rust 2021 Edition compatible, run:
97+
-->
98+
99+
`rustfix` でコードを Rust 2021 エディションに適合させるためには、次のように実行します。
36100

37101
```sh
38102
cargo fix --edition
39103
```
40104

105+
<!--
41106
Below is an examination of how to manually migrate code to use closure captures that are compatible with Rust 2021 should the automatic migration fail
42107
or you would like to better understand how the migration works.
108+
-->
109+
110+
以下では、クロージャによるキャプチャが出現するコードについて、自動移行が失敗した場合に手動で Rust 2021 に適合するように移行するにはどうすればいいかを考察します。
111+
移行がどのようになされるか知りたい人も以下をお読みください。
43112

113+
<!--
44114
Changing the variables captured by a closure can cause programs to change behavior or to stop compiling in two cases:
115+
-->
45116

117+
クロージャによってキャプチャされる変数が変わると、プログラムの挙動が変わったりコンパイルできなくなったりすることがありますが、その原因は以下の2つです:
118+
119+
<!--
46120
- changes to drop order, or when destructors run ([details](#drop-order));
47121
- changes to which traits a closure implements ([details](#trait-implementations)).
122+
-->
123+
124+
- ドロップの順序や、デストラクタが走るタイミングが変わる場合([詳細](#drop-order)
125+
- クロージャが実装するトレイトが変わる場合([詳細](#drop-order)
48126

127+
<!--
49128
Whenever any of the scenarios below are detected, `cargo fix` will insert a "dummy let" into your closure to force it to capture the entire variable:
129+
-->
130+
131+
以下のような状況を検知すると、`cargo fix` は "ダミーの let" をクロージャの中に挿入して、強制的に全ての変数がキャプチャされるようにします:
50132

133+
<!--
51134
```rust
52135
let x = (vec![22], vec![23]);
53136
let c = move || {
@@ -58,13 +141,38 @@ let c = move || {
58141
println!("{:?}", x.0);
59142
};
60143
```
144+
-->
61145

146+
```rust
147+
let x = (vec![22], vec![23]);
148+
let c = move || {
149+
// `x` 全体が強制的にキャプチャされるための "ダミーの let"
150+
let _ = &x;
151+
152+
// それがないと、`x.0` だけがここでキャプチャされる
153+
println!("{:?}", x.0);
154+
};
155+
```
156+
157+
<!--
62158
This is a conservative analysis: in many cases, these dummy lets can be safely removed and your program will work fine.
159+
-->
160+
161+
この解析は保守的です。ほとんどの場合、ダミーの let は問題なく消すことができ、消してもプログラムはきちんと動きます。
63162

163+
<!--
64164
### Wild Card Patterns
165+
-->
65166

167+
### ワイルドカードパターン
168+
169+
<!--
66170
Closures now only capture data that needs to be read, which means the following closures will not capture `x`:
171+
-->
172+
173+
クロージャは本当に読む必要のあるデータだけをキャプチャするようになったので、次のコードは `x` をキャプチャしません:
67174

175+
<!--
68176
```rust
69177
let x = 10;
70178
let c = || {
@@ -75,17 +183,50 @@ let c = || match x {
75183
_ => println!("Hello World!")
76184
};
77185
```
186+
-->
78187

188+
```rust
189+
let x = 10;
190+
let c = || {
191+
let _ = x; // 何もしない
192+
};
193+
194+
let c = || match x {
195+
_ => println!("Hello World!")
196+
};
197+
```
198+
199+
<!--
79200
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).
201+
-->
80202

203+
`_` パターンは右辺を無視するので、この `let _ = x` は何もせず、`x` はメモリ上のある場所(この場合は変数)を指し示します<!--TODO: 最後どういう意味なんでしょうか。これで訳合ってますか?-->
204+
205+
<!--
81206
This change by itself (capturing fewer values) doesn't trigger any suggestions, but it may do so in conjunction with the "drop order" change below.
207+
-->
208+
209+
この変更(いくつかの値がキャプチャされなくなること)そのものによってコード変更の提案がなされることはありませんが、後で説明する「ドロップ順序」の変更と組み合わせると、提案がなされる場合もあります。
82210

211+
<!--
83212
**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).
213+
-->
214+
215+
**ちなみに:** 似たような式の中には、同じく自動挿入される "ダミーの let" であっても、`let _ = &x` のように「何もしない」わけではない文もあります。なぜかというと、右辺(`&x`)はメモリ上のある場所を指し示すのではなく、値が評価されるべき式となるからです(その評価結果は捨てられますが)。
84216

217+
<!--
85218
### Drop Order
219+
-->
86220

221+
### ドロップの順序
222+
223+
<!--
87224
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:
225+
-->
226+
227+
クロージャが変数 `t` の所有権を取るとき、`t` がドロップされるのは `t` がスコープ外に出たときではなく、そのクロージャがドロップされたときになります:
88228

229+
<!--
89230
```rust
90231
# fn move_value<T>(_: T){}
91232
{
@@ -96,9 +237,26 @@ When a closure takes ownership of a value from a variable `t`, that value is the
96237
} // c is dropped, which drops the tuple `t` as well
97238
} // t goes out of scope here
98239
```
240+
-->
99241

242+
```rust
243+
# fn move_value<T>(_: T){}
244+
{
245+
let t = (vec![0], vec![0]);
246+
247+
{
248+
let c = || move_value(t); // t はここでムーブされる
249+
} // c がドロップされ、そのときにタプル `t` もまたドロップされる
250+
} // t はここでスコープを抜ける
251+
```
252+
253+
<!--
100254
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:
255+
-->
101256

257+
上記のコードの挙動は Rust 2018 と Rust 2021 で同じです。ところが、クロージャが変数の<!-- -->_一部_<!-- -->の所有権を取るとき、違いが発生します:
258+
259+
<!--
102260
```rust
103261
# fn move_value<T>(_: T){}
104262
{
@@ -125,28 +283,99 @@ The above code will run the same in both Rust 2018 and Rust 2021. However, in ca
125283
// remains, so it will be dropped here.
126284
}
127285
```
286+
-->
128287

288+
```rust
289+
# fn move_value<T>(_: T){}
290+
{
291+
let t = (vec![0], vec![0]);
292+
293+
{
294+
let c = || {
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+
<!--
129315
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.
316+
-->
130317

318+
ほとんどの場合、ドロップのタイミングが変わってもメモリが解放されるタイミングが変わるだけで、さほど問題にはなりません。
319+
しかし、`Drop` の実装に副作用のある(いわゆるデストラクタである)場合、ドロップの順序が変わるとプログラムの意味も変わってしまいます。
320+
その場合は、コンパイラはダミーの `let` を挿入して変数全体がキャプチャされるように提案します。
321+
322+
<!--
131323
### Trait implementations
324+
-->
325+
326+
### トレイト実装
132327

328+
<!--
133329
Closures automatically implement the following traits based on what values they capture:
330+
-->
331+
332+
何がキャプチャされているかによって、クロージャには自動的に以下のトレイトが実装されます:
134333

334+
<!--
135335
- [`Clone`]: if all captured values are [`Clone`].
136336
- [Auto traits] like [`Send`], [`Sync`], and [`UnwindSafe`]: if all captured values implement the given trait.
337+
-->
137338

339+
- [`Clone`]: キャプチャされた値がすべて [`Clone`] を実装していた場合。
340+
- [`Send`], [`Sync`], [`UnwindSafe`] などの[自動トレイト]: キャプチャされた値がすべてそのトレイトを実装していた場合。
341+
342+
<!--
138343
[auto traits]: https://doc.rust-lang.org/nightly/reference/special-types-and-traits.html#auto-traits
139344
[`clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html
140345
[`send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
141346
[`sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
142347
[`unwindsafe`]: https://doc.rust-lang.org/std/marker/trait.UnwindSafe.html
348+
-->
143349

350+
[自動トレイト]: https://doc.rust-lang.org/nightly/reference/special-types-and-traits.html#auto-traits
351+
[`clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html
352+
[`send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
353+
[`sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
354+
[`unwindsafe`]: https://doc.rust-lang.org/std/marker/trait.UnwindSafe.html
355+
356+
<!--
144357
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.
358+
-->
359+
360+
Rust 2021 では、キャプチャされる値が変わることによって、クロージャが実装するトレイトも変わることがあります。
361+
先ほどの移行リントは、それぞれのクロージャについて、これまで実装されていた自動トレイトが何であるか、そして移行後もそれらが残るかどうかを調べます。
362+
もし今まで実装されていたトレイトが実装されなくなる場合、「ダミーの let」が挿入されます。
145363

364+
<!--
146365
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.
366+
-->
147367

368+
例えば、スレッド間で生ポインタを受け渡しする一般的な方法に、ポインタを構造体でラップし、そのラッパー構造体に自動トレイト `Send`/`Sync` を実装するというものがあります。
369+
`thread::spawn` に渡されるクロージャが使うのは、ラッパー構造体のうち特定の変数だけですが、キャプチャされるのはラッパー構造体全体です。
370+
ラッパー構造体は `Send`/`Sync` なので、コードは安全であるとみなされ、コンパイルは成功します。
371+
372+
<!--
148373
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.
374+
-->
375+
376+
フィールドごとのキャプチャが導入されると、キャプチャ内で使用されているフィールドだけがキャプチャされますが、フィールドの中身はもともと `Send`/`Sync` でなかったのですから、せっかくラッパーを作っても元の木阿弥です。
149377

378+
<!--
150379
```rust
151380
use std::thread;
152381
@@ -163,3 +392,21 @@ let c = thread::spawn(move || {
163392
}
164393
}); // Closure captured px.0 which is not Send
165394
```
395+
-->
396+
397+
```rust
398+
use std::thread;
399+
400+
struct Ptr(*mut i32);
401+
unsafe impl Send for Ptr {}
402+
403+
404+
let mut x = 5;
405+
let px = Ptr(&mut x as *mut i32);
406+
407+
let c = thread::spawn(move || {
408+
unsafe {
409+
*(px.0) += 10;
410+
}
411+
}); // クロージャは px.0 をキャプチャしたが、これは Send ではない
412+
```

0 commit comments

Comments
 (0)