Rustの配列
配列(array)は、同じ型の値を決まった数だけ並べたものです。大事なのは「決まった数」というところです。配列は一度作ると、あとから大きくしたり小さくしたりできません。サイズを変えたいときに使うのはベクタです。
fn main() { let numbers: [i32; 5] = [1, 2, 3, 4, 5]; println!("{:?}", numbers);}[i32; 5] という型は「i32 の値が5個入った配列」と読みます。この長さは型の一部です。つまり、[i32; 5] と [i32; 3] は別の型として扱われます。
型はRustに推論してもらい、値だけを書くこともできます。
let numbers = [1, 2, 3, 4, 5];同じ値を繰り返す
Section titled “同じ値を繰り返す”同じ値をN個並べた配列を作るには、次の短い書き方を使います。
fn main() { let zeros = [0; 5]; // [0, 0, 0, 0, 0] println!("{:?}", zeros);}要素にアクセスする
Section titled “要素にアクセスする”角かっこを使います。番号(インデックス)は0から始まります。
fn main() { let fruits = ["りんご", "バナナ", "さくらんぼ"];
println!("{}", fruits[0]); // りんご println!("{}", fruits[2]); // さくらんぼ println!("要素数: {}", fruits.len());}範囲外アクセスはきちんと止められる
Section titled “範囲外アクセスはきちんと止められる”存在しないインデックスにアクセスしようとすると、Rustはでたらめなメモリをこっそり読むのではなく、プログラムを止めてくれます。
fn get_fruit(fruits: [&str; 3], index: usize) -> &str { fruits[index]}
fn main() { let fruits = ["りんご", "バナナ", "さくらんぼ"]; println!("{}", get_fruit(fruits, 10)); // 実行時にパニックする}thread 'main' (12345) panicked at src/main.rs:2:5:index out of bounds: the len is 3 but the index is 10このメッセージは「範囲外のインデックスです。長さは3ですが、インデックスは10です」という意味です。Rust自身が出すメッセージなので、英語のままになります。
配列をループで回す
Section titled “配列をループで回す”fn main() { let numbers = [10, 20, 30];
for n in numbers { println!("{n}"); }}配列の配列(2次元配列)
Section titled “配列の配列(2次元配列)”配列の中には、別の配列を入れられます。そうすると、ゲームの盤面や小さな表計算シートのような、行と列を持つグリッドが作れます。下の grid の型は [[i32; 3]; 2] で、「i32 が3個入った配列が2行」と読みます。
fn main() { // 2行3列 let grid = [ [1, 2, 3], [4, 5, 6], ];
println!("1行目・2列目: {}", grid[1][2]);
let mut total = 0; for row in grid { println!("{:?}", row); for value in row { total += value; } } println!("合計: {total}");}実行結果:
1行目・2列目: 6[1, 2, 3][4, 5, 6]合計: 21grid[1][2] は「1行目、そしてその行の中の2列目」という意味です。どちらも0から数えるので、これは2番目の行の3番目の値です。すべての値をたどるには、行をまわすループを1つ書き、その中に各行の値をまわすループをもう1つ書きます。
行の長さは型の一部なので、どの行も同じ長さでなければなりません。ループしながら位置も知りたいときは、.iter().enumerate() を使うとインデックスと値を一緒に受け取れます。これはforのページで紹介しています。
配列とベクタの使い分け
Section titled “配列とベクタの使い分け”サイズが決まっていて、最初からわかっているとき(1週間の7日など)は配列を使います。要素を追加したり削除したりする必要があるときは Vec を使います。実際のところ、ほとんどの場面は後者です。普段のRustのコードでは、配列はベクタほどよくは使われません。
1. 合計と平均
Section titled “1. 合計と平均”配列 [4, 8, 15, 16, 23, 42] を作ります。すべての値を足し合わせ、合計と、小数点以下2桁までの平均を表示してください。ヒント:for でループして total に足していき、割り算の前に as で両方の数を f64 に変換します。
解答を見る
fn main() { let numbers = [4, 8, 15, 16, 23, 42];
let mut total = 0; for n in numbers { total += n; }
let average = total as f64 / numbers.len() as f64; println!("合計: {total}"); println!("平均: {average:.2}");}実行結果:
合計: 108平均: 18.00as f64 がないと、total / numbers.len() は整数の割り算になってしまいます。それに、total(i32)と len()(usize)は型が違う、とRustに怒られてしまいます。
2. いちばん暑い日
Section titled “2. いちばん暑い日”1週間の気温 [18, 25, 12, 31, 22, 27, 19] があります。いちばん高い気温を見つけて表示してください。ヒント:let mut hottest = temps[0]; から始めて、ループしながら、それより大きい値が見つかるたびに置き換えます。
解答を見る
fn main() { let temps = [18, 25, 12, 31, 22, 27, 19];
let mut hottest = temps[0]; for t in temps { if t > hottest { hottest = t; } }
println!("最高気温: {hottest}");}実行結果:
最高気温: 310 ではなく temps[0] から始めるのが大事です。もし気温がすべて0度未満だったら、0 から始めると間違った答えになってしまいます。
- 配列の長さは固定で、型の一部になっています:
[i32; 5]。 - 要素には
array[index]でアクセスします。番号は0から始まります。 - 範囲外アクセスは、未定義動作になるのではなく、実行時にパニックします。
- 配列には配列を入れられます。
[[i32; 3]; 2]はグリッドで、grid[行][列]で読み出します。 - サイズを変えたいなら、代わりに
Vecを使いましょう。
理解度チェック
Section titled “理解度チェック”理解度チェック
1. Rustの配列の長さについて正しいものはどれですか?
2. 実行時に配列の範囲外のインデックスにアクセスすると、どうなりますか?
3. let zeros = [0; 5]; は何を作りますか?
スコア: 0 / 3
さらに詳しく
Section titled “さらに詳しく”- 配列型 — The Rust Programming Language 日本語版:長さが型の一部である理由も含めて、配列を紹介する公式の入門です。
- 配列とスライス — Rust By Example 日本語版:短い実行できるサンプルと、スライスの最初の紹介です。
- forでコレクションを覗き見る — The Rust Programming Language 日本語版:配列をインデックスでたどるより、
forループのほうが安全な理由がわかります。 array— 標準ライブラリのドキュメント(英語):mapやas_sliceなど配列でできることと、配列がスライスのメソッドもすべて使えるしくみを説明しています。