Code Fix

上級

E0004: non-exhaustive patterns の原因と直し方

match式は、値が取りうるすべてのパターンを網羅していなければコンパイルできません。一部のケースだけを書いて残りを省略すると、E0004エラーになります。

エラーメッセージの読み方

error[E0004]: non-exhaustive patterns: `Level::Advanced` not covered
E0004
エラーコード — `rustc --explain E0004` で詳しい説明が見られます
non-exhaustive patterns: `Level::Advanced` not covered
詳細メッセージ — 何が問題だったか

このエラーが出る典型パターン

パターン1

 1  enum Level { Beginner, Intermediate, Advanced }
 2  fn main() {
 3      let level = Level::Intermediate;
 4      let name = match level {
 5          Level::Beginner => "beginner",
 6          Level::Intermediate => "intermediate",                                       
                                                  ^
 7      };
 8      println!("{}", name);
 9  }
error[E0004]: non-exhaustive patterns: `Level::Advanced` not covered

match式はenumが取りうる全ての変体を網羅しなければコンパイルできません。Advancedのアームが抜けています。

直し方: Level::Intermediate => "intermediate",Level::Intermediate => "intermediate", Level::Advanced => "advanced", にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  enum Signal { Red, Yellow, Green }
 2  fn main() {
 3      let signal = Signal::Yellow;
 4      let action = match signal {
 5          Signal::Red => "stop",
 6          Signal::Yellow => "caution",                               
                                         ^
 7      };
 8      println!("{}", action);
 9  }
error[E0004]: non-exhaustive patterns: `Signal::Green` not covered

enumに新しい変体が増えたのにmatchのアームを追加し忘れると、このエラーが検出してくれます。

直し方: Signal::Yellow => "caution",Signal::Yellow => "caution", Signal::Green => "go", にします。

この問題を解いてみる →

パターン3

 1  enum Weather { Sunny, Rainy, Cloudy }
 2  fn main() {
 3      let w = Weather::Rainy;
 4      let msg = match w {
 5          Weather::Sunny => "bring sunscreen",
 6          Weather::Rainy => "bring umbrella",                                           
                                                   ^
 7      };
 8      println!("{}", msg);
 9  }
error[E0004]: non-exhaustive patterns: `Weather::Cloudy` not covered

switch文がフォールスルーする言語と違い、Rustのmatchは網羅性チェックが必須です。

直し方: Weather::Rainy => "bring umbrella",Weather::Rainy => "bring umbrella", Weather::Cloudy => "bring jacket", にします。

この問題を解いてみる →

パターン4

 1  enum Size { Small, Medium, Large }
 2  fn main() {
 3      let s = Size::Medium;
 4      let label = match s {
 5          Size::Small => "S",
 6          Size::Medium => "M",                            
                                    ^
 7      };
 8      println!("{}", label);
 9  }
error[E0004]: non-exhaustive patterns: `Size::Large` not covered

想定外の値を無視したい場合でも、_のワイルドカードアームを明示的に書く必要があります。

直し方: Size::Medium => "M",Size::Medium => "M", Size::Large => "L", にします。

この問題を解いてみる →

パターン5

 1  enum Role { Admin, Editor, Viewer }
 2  fn main() {
 3      let r = Role::Editor;
 4      let perm = match r {
 5          Role::Admin => "full",
 6          Role::Editor => "write",                                
                                        ^
 7      };
 8      println!("{}", perm);
 9  }
error[E0004]: non-exhaustive patterns: `Role::Viewer` not covered

network-exhaustiveのチェックのおかげで、新しいバリアントの対応漏れをコンパイル時に発見できます。

直し方: Role::Editor => "write",Role::Editor => "write", Role::Viewer => "read", にします。

この問題を解いてみる →

よくある誤解

「よくあるパターンだけ書いておけば、その他の値はスキップされて次に進むはず」という思い込みは誤りです。matchは網羅性チェックが必須で、想定外の値を無視したい場合でも_(ワイルドカード)のアームを明示する必要があります。

まとめ

E0004: non-exhaustive patternsは上級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)