1. 概要
今回はRustのベクタ、スライスについて学んでいきたいと思います。
2. ベクタ
ベクタはヒープ領域の確保される可変配列です。
ベクタの初期化には、「let 変数名: Vec<型> = Vec::new();」と書きます。また、vec!マクロを使用した初期化や、イテレーターのcollectメソッドを使用した初期化もできます。
fn main() {
// ベクタの初期化
let vect_1: Vec<String> = Vec::new();
println!("{:?}", vect_1);
// vec!マクロを使用して初期化
let vect_2 = vec!["a", "b", "c"];
println!("{:?}", vect_2);
// collectメソッドを使用して初期化
let vect_3: Vec<i32> = (0..=10).collect();
println!("{:?}", vect_3);
}
結果
Compiling hello_rust v0.1.0 (<作業ディレクトリ>/hello_rust)
Finished dev [unoptimized + debuginfo] target(s) in 40.58s
Running `target/debug/hello_rust`
[]
["a", "b", "c"]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
次に、ベクタに要素に要素を追加する方法を確認してみます。
fn main() {
// ベクタの初期化
let mut vect = Vec::new();
// 要素を追加
vect.push("a".to_string());
vect.push("b".to_string());
vect.push("c".to_string());
for i in vect {
println!("{}", i);
}
}
結果
Compiling hello_rust v0.1.0 (<作業ディレクトリ>/hello_rust)
Finished dev [unoptimized + debuginfo] target(s) in 2.74s
Running `target/debug/hello_rust`
a
b
c
要素を追加する時は、pushメソッドを使用して追加します。
次は、要素を削除する方法を確認して見ます。
fn main() {
// ベクタの初期化
let mut vect_1 = vec!["A", "B", "C", "D"];
// removeメソッドで2番目の要素を削除
vect_1.remove(1);
println!("{:?}", vect_1);
// ベクタの初期化
let mut vect_2 = vec!["A", "B", "C", "D"];
// retainメソッドを使用して条件にあった要素だけを保持、それ以外を削除
vect_2.retain(|&x| x != "C");
println!("{:?}", vect_2);
}
結果
Compiling hello_rust v0.1.0 (<作業ディレクトリ>/hello_rust)
Finished dev [unoptimized + debuginfo] target(s) in 0.64s
Running `target/debug/hello_rust`
["A", "C", "D"]
["A", "B", "D"]
まずは、removeメソッドを使用して削除しています。これは他の言語でもよく見るものだと思います。次は、retainメソッドを使用して、クロージャーに合致するものだけを、保持してそれ以外を削除します。ちなみにクロージャーとは他の言語ではラムダ式と言われるものです。
次は、要素へアクセスする方法を確認してみましょう。
fn main() {
// ベクタの初期化
let vect_1 = vec!["A", "B", "C"];
// 各要素にアクセス
println!("{}", vect_1[0]);
println!("{}", vect_1[1]);
println!("{}", vect_1[2]);
// ベクタの初期化
let vect_2 = vec!["D", "E", "F"];
// for文を使用して各要素にアクセス
for i in vect_2 {
println!("{}", i);
}
// ベクタの初期化
let mut vect_3 = vec!["G", "H", "I"];
// popメソッドを使用して末尾の要素を取り出す
println!("{:?}", vect_3.pop());
println!("{:?}", vect_3.pop());
println!("{:?}", vect_3.pop());
}
結果
Compiling hello_rust v0.1.0 (<作業ディレクトリ>/hello_rust)
Finished dev [unoptimized + debuginfo] target(s) in 0.62s
Running `target/debug/hello_rust`
A
B
C
D
E
F
Some("I")
Some("H")
Some("G")
Vec[0]やfor文でアクセスするのは他の言語でも同じような書き方なので簡単に使えるものだと思います。popメソッドは末尾の要素を取り出します。返却されるデータは値を含んだオプション型です。気をつける点は、要素を取り出すので、ミュータブルな変数として定義する必要があります。要素を取り出したあとは、対象のベクタからは削除されます。
ベクタで使用する基本的なメソッドはこれぐらいかなと思います。他にもこんなのがあるよって方は、コメントなどお願いします。
3. スライス
スライスは配列、ベクタ、文字列などの一部分を参照ためのものです。基本的に参照なので所有権の移動は発生しません。
スライスを取得するには「let 変数名 = 参照する変数&[n番目..m-1番目]」または「let 変数名 = 参照する変数&[n番目..=m-番目]」と書きます。
では、実際にプログラムで確認して見ましょう。
fn main() {
// Stringオブジェクト作成
let s = String::from("hello");
// 0番目から1番目までの要素を取得
let slice_1 = &s[0..2];
println!("{}", slice_1);
// 配列を初期化
let h = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 3番目から9番目までの要素を取得
let slice_2 = &h[3..=9];
println!("{:?}", slice_2);
}
結果
Compiling hello_rust v0.1.0 (<作業ディレクトリ>/hello_rust)
Finished dev [unoptimized + debuginfo] target(s) in 0.52s
Running `target/debug/hello_rust`
he
[3, 4, 5, 6, 7, 8, 9]
こんな感じで、指定した要素を取得できます。
次は、関数の引数にスライスを指定したプログラムを確認してみましょう。
fn main() {
let h = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
println!("合計 = {}", sum_slice(&h[..]));
println!("合計 = {}", sum_slice(&h[3..=8]));
}
// スライスの各要素を加算
fn sum_slice(item: &[i32]) -> i32 {
let mut total = 0;
for i in item {
total += i;
}
total
}
結果
Compiling hello_rust v0.1.0 (<作業ディレクトリ>/hello_rust)
Finished dev [unoptimized + debuginfo] target(s) in 0.67s
Running `target/debug/hello_rust`
合計 = 45
合計 = 33
渡されたスライスの各要素を加算するプログラムです。上記でも述べたように、スライスは基本的に参照なので、配列のスライスを引数に設定する場合は「引数: &[型]」と書きます。ちなみに全てスライスを取得する際は、「&[..]」と書きます。
5. まとめ
今回は、ベクタとスライスについてやりました。ベクタは他の言語と使い方は変わらないので、わかりやすかったです。スライスも初めて使った型ですが、だいぶわかりやすかったです。ただ、メソッドを全て網羅できたわけではないのでこれからも色々な場面で実際に使いつつ、学んでいければと思います。
投稿者プロフィール
最新の投稿
【Rust】2022年11月27日【Rust】Unsafe Rust
【Rust】2022年11月27日【Rust】列挙型
【Rust】2022年10月22日【Rust】構造体
【Rust】2022年10月18日【Rust】文字列型