【Rust】ベクタ、スライス

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. まとめ

今回は、ベクタとスライスについてやりました。ベクタは他の言語と使い方は変わらないので、わかりやすかったです。スライスも初めて使った型ですが、だいぶわかりやすかったです。ただ、メソッドを全て網羅できたわけではないのでこれからも色々な場面で実際に使いつつ、学んでいければと思います。

投稿者プロフィール

OkawaRyouta
最新の投稿

関連記事

  1. 【Rust】借用と参照、ライフタイム

  2. 【Rust】Unsafe Rust

  3. 【Rust】タプル型、配列型

  4. 【Rust】文字列型

  5. 【Rust】所有権システム、所有権の移動

  6. 【Rust】文字型、論理値型

最近の記事

  1. flutter

制作実績一覧

  1. Checkeys