Skip to content

Commit ac06333

Browse files
authored
Merge pull request #50 from TonalidadeHidrica/disjoint-capture-in-closures
「クロージャはフィールドごとにキャプチャする」を翻訳
2 parents be5e9ce + 169efca commit ac06333

File tree

3 files changed

+172
-2
lines changed

3 files changed

+172
-2
lines changed

TranslationTable.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
| diverging | 発散する〜(上の diverge を修飾語として使った場合)
7777
| documentation comment | ドキュメンテーションコメント
7878
| documentation test | ドキュメンテーションテスト
79+
| drop | ドロップ
7980
| dynamic dispatch | 動的ディスパッチ
8081
| early return | 早期リターン
8182
| edition | エディション
@@ -143,10 +144,12 @@
143144
| memory | メモリ
144145
| method | メソッド
145146
| monomorphization | 単相化
146-
| move | ムーブ
147+
| move | ムーブ(する)
148+
| move out | ムーブする、ムーブアウトする
147149
| mutability | ミュータビリティ
148150
| mutable | ミュータブル
149151
| mutable binding | ミュータブルな束縛
152+
| mutate | 変更する、書き換える
150153
| mutual-exclusion | 相互排他
151154
| null | ヌル
152155
| object-safe | オブジェクト安全

src/SUMMARY.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
- [Prelude への追加](rust-2021/prelude.md)
5757
- [デフォルトの Cargo のフィーチャリゾルバ](rust-2021/default-cargo-resolver.md)
5858
- [配列に対する IntoIterator](rust-2021/IntoIterator-for-arrays.md)
59-
- [Disjoint capture in closures](rust-2021/disjoint-capture-in-closures.md)
59+
- [クロージャはフィールドごとにキャプチャする](rust-2021/disjoint-capture-in-closures.md)
6060
- [panic マクロの一貫性](rust-2021/panic-macro-consistency.md)
6161
- [構文の予約](rust-2021/reserving-syntax.md)
6262
- [警告からエラーへの格上げ](rust-2021/warnings-promoted-to-error.md)

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

+167
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,198 @@
1+
<!--
12
# Disjoint capture in closures
3+
-->
24

5+
# クロージャはフィールドごとにキャプチャする
6+
7+
<!--
38
## Summary
9+
-->
10+
11+
## 概要
412

13+
<!--
514
- `|| a.x + 1` now captures only `a.x` instead of `a`.
615
- This can cause things to be dropped at different times or affect whether closures implement traits like `Send` or `Clone`.
716
- If possible changes are detected, `cargo fix` will insert statements like `let _ = &a` to force a closure to capture the entire variable.
17+
-->
18+
19+
- `|| a.x + 1``a` でなく `a.x` だけをキャプチャするようになりました。
20+
- これにより、ドロップのタイミングが変わったり、クロージャが `Send``Clone` を実装するかどうかが変わったりします。
21+
- `cargo fix` は、このような違いが起こりうると検出した場合、 `let _ = &a` のような文を挿入して、クロージャが変数全体をキャプチャするように強制します。
822

23+
<!--
924
## Details
25+
-->
1026

27+
## 詳細
28+
29+
<!--
1130
[Closures](https://doc.rust-lang.org/book/ch13-01-closures.html)
1231
automatically capture anything that you refer to from within their body.
1332
For example, `|| a + 1` automatically captures a reference to `a` from the surrounding context.
33+
-->
34+
35+
[クロージャ](https://doc.rust-jp.rs/book-ja/ch13-01-closures.html)は、本体の中で使用しているすべてのものを自動的にキャプチャします。
36+
例えば、`|| a + 1` と書くと、周囲のコンテキスト中の `a` への参照が自動的にキャプチャされます。
1437

38+
<!--
1539
In Rust 2018 and before, closures capture entire variables, even if the closure only uses one field.
1640
For example, `|| a.x + 1` captures a reference to `a` and not just `a.x`.
1741
Capturing `a` in its entirety prevents mutation or moves from other fields of `a`, so that code like this does not compile:
42+
-->
43+
44+
Rust 2018 以前では、クロージャに使われているのが1つのフィールドだけであっても、クロージャは変数全体をキャプチャします。
45+
例えば、 `|| a.x + 1``a.x` への参照だけでなく、`a` への参照をキャプチャします。
46+
`a` 全体がキャプチャされると、`a` の他のフィールドの値を書き換えたりムーブしたりできなくなります。従って以下のようなコードはコンパイルに失敗します:
1847

1948
```rust,ignore
2049
let a = SomeStruct::new();
2150
drop(a.x); // Move out of one field of the struct
51+
// 構造体のフィールドの1つをムーブする
2252
println!("{}", a.y); // Ok: Still use another field of the struct
53+
// OK: 構造体の他のフィールドは、まだ使える
2354
let c = || println!("{}", a.y); // Error: Tries to capture all of `a`
55+
// エラー: `a` 全体をキャプチャしようとする
2456
c();
2557
```
2658

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

67+
<!--
2968
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.
69+
-->
3070

71+
フィールドごとのキャプチャは [RFC 2229](https://github.com/rust-lang/rfcs/blob/master/text/2229-capture-disjoint-fields.md) の一部として提案されました。この RFC にはより詳しい動機が記載されています。
72+
73+
<!--
3174
## Migration
75+
-->
76+
77+
## 移行
3278

79+
<!--
3380
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.
81+
-->
3482

83+
Rust 2018 のコードベースから Rust 2021 への自動移行の支援のため、2021 エディションには、移行用のリント`rust_2021_incompatible_closure_captures` が追加されています。
84+
85+
<!--
3586
In order to have `rustfix` migrate your code to be Rust 2021 Edition compatible, run:
87+
-->
88+
89+
`rustfix` でコードを Rust 2021 エディションに適合させるためには、次のように実行します。
3690

3791
```sh
3892
cargo fix --edition
3993
```
4094

95+
<!--
4196
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
4297
or you would like to better understand how the migration works.
98+
-->
99+
100+
以下では、クロージャによるキャプチャが出現するコードについて、自動移行が失敗した場合に手動で Rust 2021 に適合するように移行するにはどうすればいいかを考察します。
101+
移行がどのようになされるか知りたい人も以下をお読みください。
43102

103+
<!--
44104
Changing the variables captured by a closure can cause programs to change behavior or to stop compiling in two cases:
105+
-->
45106

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

117+
<!--
49118
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:
119+
-->
120+
121+
以下のような状況を検知すると、`cargo fix` は「ダミーの let」をクロージャの中に挿入して、強制的に全ての変数がキャプチャされるようにします:
50122

51123
```rust
52124
let x = (vec![22], vec![23]);
53125
let c = move || {
54126
// "Dummy let" that forces `x` to be captured in its entirety
127+
// `x` 全体が強制的にキャプチャされるための「ダミーの let」
55128
let _ = &x;
56129

57130
// Otherwise, only `x.0` would be captured here
131+
// それがないと、`x.0` だけがここでキャプチャされる
58132
println!("{:?}", x.0);
59133
};
60134
```
61135

136+
<!--
62137
This is a conservative analysis: in many cases, these dummy lets can be safely removed and your program will work fine.
138+
-->
139+
140+
この解析は保守的です。ほとんどの場合、ダミーの let は問題なく消すことができ、消してもプログラムはきちんと動きます。
63141

142+
<!--
64143
### Wild Card Patterns
144+
-->
65145

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

68154
```rust
69155
let x = 10;
70156
let c = || {
71157
let _ = x; // no-op
158+
// 何もしない
72159
};
73160

74161
let c = || match x {
75162
_ => println!("Hello World!")
76163
};
77164
```
78165

166+
<!--
79167
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).
168+
-->
80169

170+
この `let _ = x` は何もしません。
171+
なぜなら、`_` パターンは右辺を無視し、さらに、`x` はメモリ上のある場所(この場合は変数)への参照だからです。
172+
173+
<!--
81174
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.
175+
-->
176+
177+
この変更(いくつかの値がキャプチャされなくなること)そのものによってコード変更の提案がなされることはありませんが、後で説明する「ドロップ順序」の変更と組み合わせると、提案がなされる場合もあります。
82178

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

185+
<!--
85186
### Drop Order
187+
-->
86188

189+
### ドロップの順序
190+
191+
<!--
87192
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:
193+
-->
194+
195+
クロージャが変数 `t` の値の所有権を取るとき、その値がドロップされるのは `t` がスコープ外に出たときではなく、そのクロージャがドロップされたときになります:
88196

89197
```rust
90198
# fn move_value<T>(_: T){}
@@ -94,10 +202,16 @@ When a closure takes ownership of a value from a variable `t`, that value is the
94202
{
95203
let c = || move_value(t); // t is moved here
96204
} // c is dropped, which drops the tuple `t` as well
205+
// c がドロップされ、そのときにタプル `t` もまたドロップされる
97206
} // t goes out of scope here
207+
// t はここでスコープを抜ける
98208
```
99209

210+
<!--
100211
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:
212+
-->
213+
214+
上記のコードの挙動は Rust 2018 と Rust 2021 で同じです。ところが、クロージャが変数の<!-- -->_一部_<!-- -->の所有権を取るとき、違いが発生します:
101215

102216
```rust
103217
# fn move_value<T>(_: T){}
@@ -108,44 +222,96 @@ The above code will run the same in both Rust 2018 and Rust 2021. However, in ca
108222
let c = || {
109223
// In Rust 2018, captures all of `t`.
110224
// In Rust 2021, captures only `t.0`
225+
// Rust 2018 では、`t` 全体がキャプチャされる。
226+
// Rust 2018 では、`t.0` だけがキャプチャされる
111227
move_value(t.0);
112228
};
113229

114230
// In Rust 2018, `c` (and `t`) are both dropped when we
115231
// exit this block.
232+
// Rust 2018 では、 `c` (と `t`) の両方が
233+
// このブロックを抜けるときにドロップされる。
116234
//
117235
// In Rust 2021, `c` and `t.0` are both dropped when we
118236
// exit this block.
237+
// Rust 2021 では、 `c` と `t.0` の両方が
238+
// このブロックを抜けるときにドロップされる。
119239
}
120240

121241
// In Rust 2018, the value from `t` has been moved and is
122242
// not dropped.
243+
// Rust 2018 では、`t` はすでにムーブされており、ここではドロップされない
123244
//
124245
// In Rust 2021, the value from `t.0` has been moved, but `t.1`
125246
// remains, so it will be dropped here.
247+
// Rust 2021 では、`t.0` はムーブされているが、
248+
// `t.1` は残っており、ここでドロップされる
126249
}
127250
```
128251

252+
<!--
129253
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.
254+
-->
255+
256+
ほとんどの場合、ドロップのタイミングが変わってもメモリが解放されるタイミングが変わるだけで、さほど問題にはなりません。
257+
しかし、`Drop` の実装に副作用のある(いわゆるデストラクタである)場合、ドロップの順序が変わるとプログラムの意味が変わってしまうかもしれません。
258+
その場合は、コンパイラはダミーの `let` を挿入して変数全体がキャプチャされるように提案します。
130259

260+
<!--
131261
### Trait implementations
262+
-->
132263

264+
### トレイト実装
265+
266+
<!--
133267
Closures automatically implement the following traits based on what values they capture:
268+
-->
269+
270+
何がキャプチャされているかによって、クロージャには自動的に以下のトレイトが実装されます:
134271

272+
<!--
135273
- [`Clone`]: if all captured values are [`Clone`].
136274
- [Auto traits] like [`Send`], [`Sync`], and [`UnwindSafe`]: if all captured values implement the given trait.
275+
-->
137276

277+
- [`Clone`]: キャプチャされた値がすべて [`Clone`] を実装していた場合。
278+
- [`Send`], [`Sync`], [`UnwindSafe`] などの[自動トレイト]: キャプチャされた値がすべてそのトレイトを実装していた場合。
279+
280+
<!--
138281
[auto traits]: https://doc.rust-lang.org/nightly/reference/special-types-and-traits.html#auto-traits
139282
[`clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html
140283
[`send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
141284
[`sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
142285
[`unwindsafe`]: https://doc.rust-lang.org/std/marker/trait.UnwindSafe.html
286+
-->
287+
288+
[自動トレイト]: https://doc.rust-lang.org/nightly/reference/special-types-and-traits.html#auto-traits
289+
[`clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html
290+
[`send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
291+
[`sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
292+
[`unwindsafe`]: https://doc.rust-lang.org/std/panic/trait.UnwindSafe.html
143293

294+
<!--
144295
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.
296+
-->
297+
298+
Rust 2021 では、キャプチャされる値が変わることによって、クロージャが実装するトレイトも変わることがあります。
299+
先ほどの移行リントは、それぞれのクロージャについて、これまで実装されていた自動トレイトが何であるか、そして移行後もそれらが残るかどうかを調べます。
300+
もし今まで実装されていたトレイトが実装されなくなる場合、「ダミーの let」が挿入されます。
145301

302+
<!--
146303
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.
304+
-->
147305

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

150316
```rust
151317
use std::thread;
@@ -162,4 +328,5 @@ let c = thread::spawn(move || {
162328
*(px.0) += 10;
163329
}
164330
}); // Closure captured px.0 which is not Send
331+
// クロージャは px.0 をキャプチャしたが、これは Send ではない
165332
```

0 commit comments

Comments
 (0)