🦀

100日後にRustをちょっと知ってる人になる: [Day 65]let-else と if-else

2022/11/19に公開

Day 65 のテーマ

Day 64 で Rust 1.65.0 のアナウンスノートを眺めてみましたが、そこに let-else 文に関する内容がありました。それについては、昨日どのような構文になるかは少し記載したのですが、元々 今までのバージョンにあった let 式の使い方との比較などは説明をしていませんでした。

つまり、今回のバージョンアップで、let-else 文が追加されることによって、今まで出来ていなかったどのような事が解決できるようになったのか、眺めてみたいかなと思います。

既存の if-let

Rust 公式ドキュメント (https://doc.rust-lang.org/) の中では if let 文について、列挙型とパターンマッチングのセクションで紹介されています。

if let を使用しないで match によるパターンマッチングをしているケースをまず見てみます。

let optional = Some(5);
match optional {
    Some(i) => {
        println!("Matched {:?}!", i)
    },
    _ => {},        
}

上記の例ではまず、Option の列挙子でタプル構造体な Some(T) に数値を入れています。それを match でマッチングさせて取り出しています。
マッチングしている対象の値が1つしかありません。match はマッチングする条件を記述するためのものなので、当然ながら複数の条件を定義できます。
今回のように対象の値を1つしか定義しないパターンマッチングならば、if let という記法の方がシンプルに記述できます。

ちなみに、この if let ですが、if let ではないことに注意してください。iflet を組み合わせて利用しているように一見見えてしまいますが、この if let は1つのキーワードとして定義されているものです。

そして、以下のように書き直せます。

if let Some(i) = optional {
    println!("Matched {:?}!", i);
}

ここの意味は let Some(i) = optional が、真なのか偽なのかを判定しています。
この let は代入という意味よりはパターンマッチングとして使われています。

// EXPRESSION: 何らかの値を返す「式」のこと
// PATTERN: 値がマッチするか否かに用いられる「パターン」のこと
let PATTERN = EXPRESSION;

もちろんパターンにマッチしない場合のケースとして、else を使用可能です。else の後のブロックで束縛を行います。

if let Some(i) = optional {
    println!("マッチしました {:?}!", i);
} else {
    rintln!{"マッチしません {:?}!", i};
}

match で記述するよりも随分とシンプルになりますよね。

let-else

新しく導入された let-else は次のような構文でした。

let パターン =else { never型を返す処理 };

つまり、if-let とはパターンに対してマッチする場合の変数を束縛することは共通しています。
異なっているのは、どこで束縛しているかという点です。

  • if-let: 阿多田らしく作ったブロック内で変数を束縛
    • 真の時と偽の時の処理は対等
  • let-else: 現在のブロックで変数を束縛
    • 真の時のが想定処理で else は異常系という意味が強い

実施する内容は似てはいるのですが、書き方の意味合いや束縛した変数の使いまわしなどによって、if-elselet-else かの選択肢の幅が増えそうなのかと思いました。

Day 65 のまとめ

もともと if-else を使っていた人たちにとっては、1.65.0 で新しく安定化した let-else は便利な構文と感じられているのではないかなと思いました。
Rust は条件やマッチングに関する記述の仕方が豊富だと改めて感じるリリース内容でした。

GitHubで編集を提案

Discussion