見出し画像

スーパー雑な Rust メモ : 何気ないパターンマッチ

Rust の覚書日記です。

書籍を読んでいてこんなようなコードを見かけ、「ああ、Rust だねぇ」と思いました。

fn main() {
    let v = vec![100, 200, 300,];

    // *1
    for tpl in v.iter().enumerate() {
        println!("tuple.n {}: {}", tpl.0, tpl.1); 
    }

    // *2
    for (i, n) in v.iter().enumerate() {
        println!("pattern match {}: {}", i, n); 
    }

    // *3
    println!("vec {:?}", v); 
}

v という変数で作成した Vector を使い回せるように、*1 でも *2 でも .iter() を使ってイテレートしています。このメソッドは、値の所有権を移動しません(値を消費しません、参照するだけ。なので最後の *3 で v をそのまま印字できます)。

その上で、.enumerate() を呼び出していますが、このメソッドは、添字と値のタプルを返します。

サンプルの *1 のように、tpl というひとつの変数で受け取ると、その中身はタプルです。
なので、値を取り出すときに tpl.0, tpl.1 のような取り出し方をしています。

実際のコーディングではこのような for 文の書き方は特別な理由がなければしないかな、と思います。

通常は *2 の for (i, n) in ... のようにタブルの中にその後使いたい変数名の形で指定して値を受け取ります。

こうすると、enumerate がタプルでくるんで供給してくれたものの中身に直接アクセスできますね。

***

なんらかの構造の中に組み込まれた値に変数を割り当てて、そのパターンにマッチしたら直接目的のところにアクセスできる、というのが Rust の特徴の一つです。

この特徴がフル活用されるのが match 式です。

fn main() {
    let status_name_list = [(true, "John"), (false, "Kate"),];
    for status_name in status_name_list {
        match status_name {
            (true, name) => println!("{} is alive.", name),
            (false, name) => println!("{} is dead.", name),
        }
    }
}

for が受け取っている status_name という変数には、中身的に (true, "John") の形 → 型で言うと (boolean, str) のタプルが入ります。

for 文の中の match 式では、true か false かの部分は条件分岐に使い、"John" (または "Kate")の部分の方は name という変数で値を受け取って、その後の処理で使用しています。

SN

この記事が気に入ったらサポートをしてみませんか?