diff --git a/listings/ch08-common-collections/listing-08-04/src/main.rs b/listings/ch08-common-collections/listing-08-04/src/main.rs index abda2db66..bae2b87e0 100644 --- a/listings/ch08-common-collections/listing-08-04/src/main.rs +++ b/listings/ch08-common-collections/listing-08-04/src/main.rs @@ -3,7 +3,7 @@ fn main() { { let v = vec![1, 2, 3, 4]; - // do stuff with v - } // <- v goes out of scope and is freed here + // vで作業をする + } // <- vはここでスコープを抜け、解放される // ANCHOR_END: here } diff --git a/listings/ch08-common-collections/listing-08-05/src/main.rs b/listings/ch08-common-collections/listing-08-05/src/main.rs index 9bfa37a4c..185ed8eae 100644 --- a/listings/ch08-common-collections/listing-08-05/src/main.rs +++ b/listings/ch08-common-collections/listing-08-05/src/main.rs @@ -6,7 +6,9 @@ fn main() { println!("The third element is {}", third); match v.get(2) { + // "3つ目の要素は{}です" Some(third) => println!("The third element is {}", third), + // "3つ目の要素はありません。" None => println!("There is no third element."), } // ANCHOR_END: here diff --git a/listings/ch08-common-collections/listing-08-07/output.txt b/listings/ch08-common-collections/listing-08-07/output.txt index b50110bdb..a46e34ee7 100644 --- a/listings/ch08-common-collections/listing-08-07/output.txt +++ b/listings/ch08-common-collections/listing-08-07/output.txt @@ -1,16 +1,20 @@ $ cargo run Compiling collections v0.1.0 (file:///projects/collections) error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable +(エラー: 不変としても借用されているので、`v`を可変で借用できません) --> src/main.rs:6:5 | 4 | let first = &v[0]; | - immutable borrow occurs here + | (不変借用はここで発生しています) 5 | 6 | v.push(6); | ^^^^^^^^^ mutable borrow occurs here + | (可変借用はここで発生しています) 7 | 8 | println!("The first element is: {}", first); | ----- immutable borrow later used here + | (その後、不変借用はここで使われています) error: aborting due to previous error diff --git a/src/ch08-01-vectors.md b/src/ch08-01-vectors.md index 1545b1637..102fda763 100644 --- a/src/ch08-01-vectors.md +++ b/src/ch08-01-vectors.md @@ -2,19 +2,19 @@ ## Storing Lists of Values with Vectors --> -## ベクタで一連の値を保持する +## ベクタで値のリストを保持する -最初に見るコレクションは、`Vec`であり、*ベクタ*としても知られています。ベクタは、 -メモリ上に値を隣り合わせに並べる単独のデータ構造に2つ以上の値を保持させてくれます。 -ベクタには、同じ型の値しか保持できません。要素のリストがある場合に有用です。 +最初に見るコレクション型は、`Vec`であり、これは*ベクタ*としても知られています。ベクタは、 +メモリ上に値を隣り合わせに並べる単独のデータ構造で、2つ以上の値を保持することができます。 +ベクタには、同じ型の値しか保持できません。要素のリストがある場合にベクタは有用です。 例えば、テキストファイルの各行とか、ショッピングカートのアイテムの価格などです。 -ここでは、型注釈を付け足したことに注目してください。このベクタに対して、何も値を挿入していないので、 -コンパイラには、どんなデータを保持させるつもりなのかわからないのです。これは重要な点です。ベクタは、 +ここで、型注釈を付けていることに注目してください。このベクタに対して、何も値を挿入していないので、 +コンパイラには、私達がどんなデータを保持させるつもりなのかがわからないのです。これは重要な点です。ベクタは、 ジェネリクスを使用して実装されているのです; 独自の型でジェネリクスを使用する方法については、 第10章で解説します。今は、標準ライブラリにより提供されている`Vec`型は、どんな型でも保持でき、 特定のベクタが特定の型を保持するとき、その型は山かっこ内に指定されることを知っておいてください。 @@ -62,19 +62,22 @@ hold elements of the `i32` type. より現実的なコードでは、一旦値を挿入したら、コンパイラは保持させたい値の型をしばしば推論できるので、 この型注釈をすることは滅多にありません。初期値のある`Vec`を生成する方が一般的ですし、 Rustには、利便性のために`vec!`というマクロも用意されています。このマクロは、 与えた値を保持する新しいベクタ型を生成します。リスト8-2では、`1`、`2`、`3`という値を持つ新しい`Vec`を生成しています。 +整数型を`i32`にしているのは、3章の[「データ型」][data-types]節で学んだようにこれが標準の整数型だからです。 ```rust -let v = vec![1, 2, 3]; +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-02/src/main.rs:here}} ``` -他のあらゆる`構造体`同様、ベクタもスコープを抜ければ、解放されます。リスト8-4に注釈したようにですね。 - - - - +他のあらゆる`struct`(構造体)同様、ベクタもスコープを抜ければ、解放されます。リスト8-4に注釈したようにですね。 - ```rust -{ - let v = vec![1, 2, 3, 4]; - - // vで作業をする - -} // <- vはここでスコープを抜け、解放される +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-04/src/main.rs:here}} ``` ベクタがドロップされると、その中身もドロップされます。つまり、保持されていた整数値が、 -片付けられるということです。これは一見単純な点に見えるかもしれませんが、ベクタの要素への参照を導入した途端、 +片付けられるということです。これは一見単純に見えるかもしれませんが、ベクタの要素への参照を導入した途端、 もうちょっと複雑になる可能性を秘めています。次は、それに挑んでいきましょう! -もうベクタを生成し、更新し、破棄する方法を知ったので、中身を読む方法を知るのはいいステップアップです。 -ベクタに保持された値を参照する方法は2つあります。例では、さらなる明瞭性を求めて、 +ベクタを生成し、更新し、破壊する方法を知ったので、中身を読む方法を次に知ることにしましょう。 +ベクタに保持された値を参照する方法は2つあります。これから示す例では、さらに明確にするため、 これらの関数から返る値の型を注釈しました。 ここでは、2つのことに注目してください。まず、3番目の要素を得るのに`2`という添え字の値を使用していることです: -ベクタは、数値により順序付けされ、添え字は0から始まります。2番目に、3番目の要素を得る2つの方法は、 -`&`と`[]`を使用して参照を得るものと、番号を引数として`get`メソッドに渡して、`Option<&T>`を得るものということです。 +ベクタは、数値により順序付けされ、添え字は0から始まります。2番目に、3番目の要素を得る2つの方法とは、 +`&`と`[]`を使用して参照を得るものと、番号を引数として`get`メソッドに渡して、`Option<&T>`を得るものだということです。 Rustには要素を参照する方法が2通りあるので、ベクタに要素が含まれない番号の値を使用しようとした時に、 -プログラムの振る舞いを選択できます。例として、ベクタに5つ要素があり、添え字100の要素にアクセスを試みた場合、 -プログラムがすることを確認しましょう。リスト8-6に示したようにですね。 - -```rust,should_panic -let v = vec![1, 2, 3, 4, 5]; +プログラムの振る舞いを選択できます。例として、ベクタに5つ要素があるとして、添え字100の要素にアクセスを試みた場合、 +プログラムがどうなるのか確認しましょう。リスト8-6に示したようにですね。 -let does_not_exist = &v[100]; -let does_not_exist = v.get(100); +```rust,should_panic,panics +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-06/src/main.rs:here}} ``` @@ -287,37 +260,32 @@ value. That would be more user-friendly than crashing the program due to a typo! --> `get`メソッドがベクタ外の添え字を渡されると、パニックすることなく`None`を返します。 -普通の状態でも、ベクタの範囲外にアクセスする可能性がある場合に、このメソッドを使用することになるでしょう。 -そうしたら、コードには`Some(&element)`か`None`を扱うロジックが存在することになります。そう、 -第6章で議論したように。例えば、添え字は人間に数値を入力してもらうことで得ることもできます。 +普通の状況でもベクタの範囲外にアクセスする可能性がある場合に、このメソッドを使用することになるでしょう。 +そうしたら、第6章で議論したように、コードには`Some(&element)`か`None`を扱うロジックが存在することになります。 +例えば、添え字は人間に数値を入力してもらうことで得ているのかもしれません。 もし大きすぎる値を誤って入力し、プログラムが`None`値を得てしまったら、現在ベクタに幾つ要素があるかをユーザに教え、 -再度正しい値を入力してもらうことができるでしょう。その方が、タイプミスでプログラムをクラッシュさせるより、 +再度正しい値を入力してもらうことができるでしょう。その方が、(ただの)タイプミスでプログラムをクラッシュさせるより、 ユーザに優しくなるでしょう。 -プログラムに有効な参照がある場合、借用チェッカー(borrow checker)は(第4章で解説しましたが)、 +プログラムに有効な参照がある場合、借用チェッカー (borrow checker) は (第4章で解説しましたが)、 所有権と借用規則を強制し、ベクタの中身へのこの参照や他のいかなる参照も有効であり続けることを保証してくれます。 同一スコープ上では、可変と不変な参照を同時には存在させられないというルールを思い出してください。 -このルールはリスト8-7にも適用され、リスト8-7ではベクタの最初の要素への不変参照を保持し、 -終端に要素を追加しようとしていますが、動きません。 +このルールはリスト8-7でも適用されています。リスト8-7ではベクタの最初の要素への不変参照を保持しつつ、 +終端に要素を追加しようとしています。 +関数内のここ以降で、この要素(訳注:`first`のこと)を参照しようとすると失敗します。 -```rust,ignore -let mut v = vec![1, 2, 3, 4, 5]; - -let first = &v[0]; - -v.push(6); - -println!("The first element is: {}", first); +```rust,ignore,does_not_compile +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-07/src/main.rs:here}} ``` -リスト8-7のコードは、一見動くはずのように見えるかもしれません: なぜ、最初の要素への参照が、 -ベクタの終端への変更を気にかける必要があるのでしょうか?このエラーは、ベクタの動作法のせいです: +リスト8-7のコードは、一見動くはずに見えるかもしれません: なぜ、最初の要素への参照が、 +ベクタの終端への変更を気にかける必要があるのでしょうか?このエラーは、ベクタの動作する仕組みのせいです: 新規要素をベクタの終端に追加すると、ベクタが現在存在する位置に隣り合って要素を入れるだけの領域がなかった場合に、 -メモリの新規確保をして古い要素を新しいスペースにコピーする必要があるかもしれないからです。 -その場合、最初の要素を指す参照は、解放されたメモリを指すことになるでしょう。借用規則により、 -そのような場面に陥らないよう回避されるのです。 +メモリを新規に確保して、古い要素をその新しいスペースにコピーする必要があるかもしれないからです。 +その場合、最初の要素を指す参照は、解放されたメモリを指すことになるでしょう。 +借用規則がそのような場面に陥らないよう防いでくれるのです。 -> 注釈: `Vec`の実装に関する詳細については、[“The Rustonomicon”](https://doc.rust-lang.org/stable/nomicon/vec.html)を参照してください。 - -> 訳注: 日本語版のThe Rustonomiconは[こちら][nomicon-ja-vec]です。 +> 注釈: `Vec`の実装に関する詳細については、[“The Rustonomicon”][nomicon]を参照してください (訳注:日本語版は[こちら][nomicon-ja-vec]です)。 [nomicon-ja-vec]: https://doc.rust-jp.rs/rust-nomicon-ja/vec.html ### ベクタの値を走査する -ベクタの要素に順番にアクセスしたいなら、添え字で1回に1要素にアクセスするのではなく、全要素を走査することができます。 +ベクタの要素に順番にアクセスしたいなら、添え字で1要素ごとにアクセスするのではなく、全要素を走査することができます。 リスト8-8で`for`ループを使い、`i32`のベクタの各要素に対する不変な参照を得て、それらを出力する方法を示しています。 ```rust -let v = vec![100, 32, 57]; -for i in &v { - println!("{}", i); -} +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-08/src/main.rs:here}} ``` -全要素に変更を加える目的で、可変なベクタの各要素への可変な参照を走査することもできます。 +全要素に変更を加えるために、可変なベクタの各要素への可変な参照を走査することもできます。 リスト8-9の`for`ループでは、各要素に`50`を足しています。 ```rust -let mut v = vec![100, 32, 57]; -for i in &mut v { - *i += 50; -} +{{#rustdoc_include ../listings/ch08-common-collections/listing-08-09/src/main.rs:here}} ``` 可変参照が参照している値を変更するには、`+=`演算子を使用する前に、 参照外し演算子(`*`)を使用して`i`の値に辿り着かないといけません。 +参照外し演算子については、15章の[「参照外し演算子で値までポインタを追いかける」][deref]節でより詳しく扱います。 この章の冒頭で、ベクタは同じ型の値しか保持できないと述べました。これは不便なこともあります; -異なる型の要素を保持する必要性が出てくるユースケースも確かにあるわけです。幸運なことに、 -enumの列挙子は、同じenumの型の元に定義されるので、ベクタに異なる型の要素を保持する必要が出たら、 -enumを定義して使用することができます! +異なる型の要素を保持する必要性が出てくるユースケースもきっとあります。幸運なことに、 +enumの列挙子は、同じenumの型の中に定義されるので、ベクタに異なる型の要素を保持する必要が出たら、 +enumを定義して使用すればよいというわけです! -各要素を格納するのにヒープ上でズバリどれくらいのメモリが必要になるかをわかるように、 -コンパイラがコンパイル時にベクタに入る型を知る必要があります。副次的な利点は、 -このベクタではどんな型が許容されるのか明示できることです。もしRustでベクタがどんな型でも保持できたら、 -ベクタの要素に対して行われる処理に対して一つ以上の型がエラーを引き起こす可能性があったでしょう。 -enumに加えて`match`式を使うことは、第6章で議論した通り、コンパイル時にありうる場合全てに対処していることをコンパイラが、 -保証できることを意味します。 +各要素を格納するのにヒープ上でズバリどれくらいのメモリが必要になるかがわかるように、 +Rustコンパイラはコンパイル時にベクタに入る型を知る必要があります。また、 +このベクタではどんな型が許容されるのか明示できるという副次的な利点があります。もし、Rustコンパイラが、ベクタがどんな型でも保持できるようにしていたら、 +ベクタの要素に対して行われる処理に対して一つ以上の型がエラーを引き起こす可能性があるでしょう。 +enumに加えて`match`式を使うことは、第6章で議論した通り、あり得るパターン全てに対処していることをRustコンパイラがコンパイル時に保証するということを意味します。 -プログラム記述時にプログラムがベクタに実行時に保持するありとあらゆる一連の型をプログラマが知らない場合、 -このenumテクニックはうまく動かないでしょう。代わりにトレイトオブジェクトを使用することができ、こちらは第17章で講義します。 +プログラムを書いている時に、プログラムが実行時に受け取り、ベクタに保持するであろう型のすべてを知っているわけではない場合、 +このenumを使ったテクニックはうまくいかないでしょう。代わりにトレイトオブジェクトを使用することができます。こちらは第17章で講義します。 +今まで議論したのは、ベクタを使用するために最もよく使う方法のいくつか(に過ぎない)です。 +ですので、標準ライブラリで`Vec`に定義されている多くの有益なメソッドについて、 +[APIドキュメント][vec-api]を必ず確認するようにしてください。例えば、`push`に加えて、`pop`というメソッドがあり、これは最後の要素を削除して返します。 +それでは次のコレクション型に移りましょう: `String`です! + -今や、ベクタを使用するべき最も一般的な方法について触れ、議論したので、標準ライブラリで`Vec`に定義されている多くの有益なメソッドについては、 -APIドキュメントを確認することを心得てください。例として、`push`に加えて、`pop`メソッドは最後の要素を削除して返します。 -次のコレクション型に移りましょう: `String`です! +[data-types]: ch03-02-data-types.html#データ型 +[nomicon]: ../nomicon/vec.html +[vec-api]: ../std/vec/struct.Vec.html +[deref]: ch15-02-deref.html#参照外し演算子で値までポインタを追いかける