Rust のパターンマッチングにおける反証可能性

RustRustBeginner
オンラインで実践に進む

This tutorial is from open-source community. Access the source code

💡 このチュートリアルは英語版からAIによって翻訳されています。原文を確認するには、 ここをクリックしてください

はじめに

反証可能性:パターンが一致しない可能性があるかどうかへようこそ。この実験は、Rust Bookの一部です。LabEx で Rust のスキルを練習することができます。

この実験では、パターンにおける反証可能性の概念と、それが Rust のマッチングプロセスにどのように影響するかを学びます。これには、反証可能なパターンと反証不可能なパターンの違い、およびlet文やif let式などのさまざまな構文でそれらを正しく使用する方法が含まれます。

反証可能性:パターンが一致しない可能性があるかどうか

パターンには 2 つの形式があります。反証可能なパターンと反証不可能なパターンです。渡される任意の可能な値に対して一致するパターンは、反証不可能なパターンです。例としては、let x = 5;という文のxです。なぜならxは何にでも一致するため、一致しないことはありません。一部の可能な値に対して一致しない可能性のあるパターンは、反証可能なパターンです。例としては、if let Some(x) = a_valueという式のSome(x)です。なぜなら、a_value変数の値がNoneである場合、Some(x)パターンは一致しないからです。

関数のパラメータ、let文、およびforループは、値が一致しない場合に何も意味のあることができないため、反証不可能なパターンのみを受け付けます。if letおよびwhile let式は、反証可能なパターンと反証不可能なパターンの両方を受け付けますが、コンパイラは反証不可能なパターンに対して警告を出します。なぜなら、定義上、それらは失敗の可能性を処理するために意図されているからです。条件分岐の機能は、成功または失敗に応じて異なる動作を行う能力にあります。

一般的に、反証可能なパターンと反証不可能なパターンの違いを心配する必要はありません。ただし、反証可能性の概念に慣れておく必要があります。そうすれば、エラーメッセージでそれを見たときに対応できます。そのような場合、コードの意図された動作に応じて、パターンまたはパターンを使用している構文のいずれかを変更する必要があります。

Rust が反証不可能なパターンを必要とする場合に反証可能なパターンを使用しようとしたとき、およびその逆の場合に何が起こるかを見てみましょう。リスト 18-8 はlet文を示していますが、パターンとして、反証可能なパターンであるSome(x)を指定しています。予想通り、このコードはコンパイルされません。

let Some(x) = some_option_value;

リスト 18-8:letに反証可能なパターンを使用しようとする

some_option_valueNoneの値である場合、パターンSome(x)と一致しなくなります。これは、パターンが反証可能であることを意味します。ただし、let文は反証不可能なパターンのみを受け付けることができます。なぜなら、Noneの値ではコードが何も有効なことをできないからです。コンパイル時に、Rust は反証不可能なパターンが必要な場所で反証可能なパターンを使用しようとしたことをコンパイラエラーとして通知します。

error[E0005]: refutable pattern in local binding: `None` not covered
   --> src/main.rs:3:9
    |
3   |     let Some(x) = some_option_value;
    |         ^^^^^^^ pattern `None` not covered
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or
an `enum` with only one variant
    = note: for more information, visit
https://doc.rust-lang.org/book/ch18-02-refutability.html
    = note: the matched value is of type `Option<i32>`
help: you might want to use `if let` to ignore the variant that isn't matched
    |
3   |     let x = if let Some(x) = some_option_value { x } else { todo!() };
    |     ++++++++++                                 ++++++++++++++++++++++

パターンSome(x)ですべての有効な値をカバー(およびカバーできなかった!)していないため、Rust は正しくコンパイラエラーを生成します。

反証不可能なパターンが必要な場所に反証可能なパターンがある場合、パターンを使用するコードを変更することで修正できます。letを使用する代わりに、if letを使用することができます。そうすると、パターンが一致しない場合、コードは波括弧内のコードをスキップし、正常に続行する方法が与えられます。リスト 18-9 は、リスト 18-8 のコードを修正する方法を示しています。

if let Some(x) = some_option_value {
    println!("{x}");
}

リスト 18-9:letの代わりにif letと反証可能なパターンを持つブロックを使用する

コードに抜け道があります!このコードは完全に有効です。ただし、エラーを受け取らずに反証不可能なパターンを使用することはできません。リスト 18-10 に示すように、if letに常に一致するパターン(たとえばx)を与えると、コンパイラは警告を出します。

if let x = 5 {
    println!("{x}");
};

リスト 18-10:if letに反証不可能なパターンを使用しようとする

Rust は、反証不可能なパターンを持つif letを使用することは意味がないとコンパイラエラーを表示します。

warning: irrefutable `if let` pattern
 --> src/main.rs:2:8
  |
2 |     if let x = 5 {
  |        ^^^^^^^^^
  |
  = note: `#[warn(irrefutable_let_patterns)]` on by default
  = note: this pattern will always match, so the `if let` is
useless
  = help: consider replacing the `if let` with a `let`

このため、matchのアームは、最後のアームを除き、反証可能なパターンを使用する必要があります。最後のアームは、反証不可能なパターンで残りのすべての値と一致する必要があります。Rust は、1 つのアームしか持たないmatchで反証不可能なパターンを使用することを許可していますが、この構文は特に役に立たず、より単純なlet文に置き換えることができます。

これで、パターンを使用する場所と反証可能なパターンと反証不可能なパターンの違いがわかりました。次に、パターンを作成するために使用できるすべての構文を説明します。

まとめ

おめでとうございます!「反証可能性:パターンが一致しない可能性があるかどうか」の実験を完了しました。LabEx でさらに多くの実験を行って、スキルを向上させることができます。