Rustのベクタ
ベクタ(vector、Vec)は配列に似ていますが、実行中に大きくしたり小さくしたりできます。普段のRustのコードで「何かのリスト」が必要になったら、固定長の配列よりも Vec を使うことのほうがずっと多いでしょう。
ベクタを作る
Section titled “ベクタを作る”fn main() { let numbers: Vec<i32> = vec![1, 2, 3]; println!("{:?}", numbers);}vec![] はマクロ(! がついていますね)で、値の並びから Vec を作ってくれます。配列リテラルを書くのと同じような感覚で使えます。
空の状態から始めて、あとから要素を足していくこともできます。
let mut numbers: Vec<i32> = Vec::new();要素を追加する
Section titled “要素を追加する”末尾に追加するには .push() を使います。ベクタを変更するので、mut をつける必要があります。
fn main() { let mut numbers = Vec::new();
numbers.push(1); numbers.push(2); numbers.push(3);
println!("{:?}", numbers);}実行結果:
[1, 2, 3]要素にアクセスする
Section titled “要素にアクセスする”配列と同じ角かっこの書き方です。
fn main() { let fruits = vec!["りんご", "バナナ", "さくらんぼ"];
println!("{}", fruits[0]); println!("要素数: {}", fruits.len());}おかしなインデックスでもパニックしない、より安全な取り出し方がほしいときは .get() を使います。これは値の代わりに Option を返します(詳しくは Option のページで説明します)。
fn main() { let fruits = vec!["りんご", "バナナ", "さくらんぼ"];
match fruits.get(10) { Some(fruit) => println!("見つかりました: {fruit}"), None => println!("そのインデックスに果物はありません"), }}要素を削除する
Section titled “要素を削除する”fn main() { let mut numbers = vec![1, 2, 3, 4, 5];
numbers.pop(); // 最後の要素を削除 -> [1, 2, 3, 4] numbers.remove(0); // インデックスで削除 -> [2, 3, 4]
println!("{:?}", numbers);}ベクタをループで回す
Section titled “ベクタをループで回す”fn main() { let numbers = vec![10, 20, 30];
for n in &numbers { println!("{n}"); }}numbers の前の & に注目してください。for n in &numbers と書くと、ベクタの所有権を奪うのではなく、各要素を借用します。& をつけないと、ベクタはループの中にムーブ(move)されてしまい、そのあと numbers を使えなくなります。ほとんどの場合、ほしいのは借用のほうです。
ジェネリクスについてひとこと
Section titled “ジェネリクスについてひとこと”型が Vec<i32> と書かれていることに気づいたでしょうか。<i32> の部分は「i32 の値のベクタ」という意味です。このかっこを使った書き方をジェネリクス(generics)と呼びます。きちんとした説明はジェネリクスのページでします。今のところは、Vec<T> を「T 型の値を入れるベクタ」と読めば十分です。
1. 偶数を集める
Section titled “1. 偶数を集める”空のベクタから始めます。1から10までの数をループして、偶数だけを push してください。最後に、ベクタとその要素数を表示しましょう。ヒント:n % 2 == 0 のとき、数 n は偶数です。
解答を見る
fn main() { let mut evens = Vec::new();
for n in 1..=10 { if n % 2 == 0 { evens.push(n); } }
println!("{:?}", evens); println!("偶数は{}個見つかりました", evens.len());}実行結果:
[2, 4, 6, 8, 10]偶数は5個見つかりました型を一度も書いていないことに注目してください。Rustは push(n) の呼び出しを見て、evens が Vec<i32> だと判断してくれます。
2. 積み重ねたお皿
Section titled “2. 積み重ねたお皿”ベクタに3枚のお皿を push します:"青"、"緑"、そして "赤"。.pop() で上から2枚取り、それぞれを表示してください。最後に、残っているものを表示します。ヒント:.pop() は Option を返すので、{:?} で表示します。
解答を見る
fn main() { let mut plates = Vec::new(); plates.push("青"); plates.push("緑"); plates.push("赤");
println!("取った: {:?}", plates.pop()); println!("取った: {:?}", plates.pop()); println!("残り: {:?}", plates);}実行結果:
取った: Some("赤")取った: Some("緑")残り: ["青"]pop() は、積み重ねたお皿の一番上を取るように、いつも最後に push した要素を取り出します。ただの値ではなく Some(...) を返すのは、ベクタが空かもしれないからです。空のときは、クラッシュする代わりに None が返ってきます。
Vec<T>は伸び縮みできるリストです。vec![...]かVec::new()で作ります。.push()は末尾に追加し、.pop()は最後の要素を削除し、.remove(i)はインデックスを指定して削除します。vec[i]はおかしなインデックスでパニックします。.get(i)は代わりにOptionを返すので、パニックしません。for item in &vecでループすると、ベクタを消費せずに要素を借用できます。
理解度チェック
Section titled “理解度チェック”理解度チェック
1. numbers[10] のように、範囲外のインデックスで Vec にアクセスするとどうなりますか?
2. パニックの心配なくインデックスで値を取り出せるメソッドはどれですか?
3. for n in &numbers の & は何をしていますか?
スコア: 0 / 3
さらに詳しく
Section titled “さらに詳しく”- ベクタで値のリストを保持する — The Rust Programming Language 日本語版:ベクタの作成、読み出し、更新と、参照を持ったまま
pushできない理由を説明しています。 - ベクタ型 — Rust By Example 日本語版:よく使う
Vecの操作をまとめて見られる、実行できるサンプルです。 Vec— 標準ライブラリのドキュメント(英語):insert、retain、extend、containsなど、すべてのメソッドの一覧です。- The
vec!macro — 標準ライブラリのドキュメント(英語):同じ値を繰り返すvec![0; 10]も含めた、vec!のすべての書き方です。