Rustのエラー E0027: pattern does not mention field x(パターンのフィールド漏れ)
E0027 は、let Order { item, quantity } = order; のようなパターンで構造体や列挙型のバリアントを分解しようとしたけれど、すべてのフィールドに触れていない、という意味のエラーです。Rust では、構造体のパターンはすべてのフィールドを扱わなければなりません。名前を書くか、.. で「残りは全部」と言うかのどちらかです。これはいちばん親切なエラーの1つです。rustc が正確な直し方を表示してくれて、それはほとんどの場合、点2つだけです。このシリーズのほかのエラーは、Rustのコンパイルエラー解説を見てください。
エラーメッセージ
Section titled “エラーメッセージ”error[E0027]: pattern does not mention fields `id`, `paid` --> src/main.rs:10:9 |10 | let Order { item, quantity } = order; // ❌ `id` and `paid` are not mentioned | ^^^^^^^^^^^^^^^^^^^^^^^^ missing fields `id`, `paid` |help: include the missing fields in the pattern |10 | let Order { item, quantity, id, paid } = order; // ❌ `id` and `paid` are not mentioned | ++++++++++help: if you don't care about these missing fields, you can explicitly ignore them |10 | let Order { item, quantity, id: _, paid: _ } = order; // ❌ `id` and `paid` are not mentioned | ++++++++++++++++help: or always ignore missing fields here |10 | let Order { item, quantity, .. } = order; // ❌ `id` and `paid` are not mentioned | ++++「pattern does not mention fields id, paid」は「パターンがフィールド id と paid に触れていない」という意味です。
このエラーが出るのは、次のプログラムです。
struct Order { id: u32, item: String, quantity: u32, paid: bool,}
fn main() { let order = Order { id: 1, item: String::from("keyboard"), quantity: 2, paid: true }; let Order { item, quantity } = order; // ❌ `id` and `paid` are not mentioned println!("{} x {}", quantity, item);}コメントは「id と paid に触れていない」という意味です(エラーになる例なので、コードはそのままにしています)。
エラーの意味
Section titled “エラーの意味”見出しの行には、パターンで書き漏らしたフィールド(id と paid)が並んでいます。^^^ はパターン全体に引かれています。問題は1つの間違った単語ではなく、何かが足りないことだからです。
続いて rustc は、3つの help: を出します。どれも正しい直し方ですが、意味はそれぞれ違います。
include the missing fields(足りないフィールドをパターンに含める):名前を書きます。idとpaidという変数も手に入ります。explicitly ignore them(はっきり無視する):id: _, paid: _と書きます。変数は作られませんが、すべてのフィールドを名前で並べたことになります。always ignore missing fields here(ここでは足りないフィールドをいつも無視する):..と書きます。「ほかのフィールドがあっても、気にしない」という意味です。
入り口のチェックリストに「すべての欄にチェックを入れるか、『その他:飛ばす』にチェックを入れてください」と書いてあるようなものです。空欄のまま出すことはできません。
Rust がこうする理由
Section titled “Rust がこうする理由”Rust の構造体のパターンは、特に何も言わなければ完全であることになっています。こうすると、あとで読む人に意図がはっきり伝わります。Order { item, quantity, .. } は「この2つだけ必要」と言っています。Order { id, item, quantity, paid } は「すべてのフィールドについて考えた」と言っています。詳しくは_ と .. で一部を無視するを見てください。
本当にありがたいのは、構造体が変わったときです。誰かが Order に discount フィールドを追加すると、すべてのフィールドを名前で並べたパターンは E0027 で壊れます。新しいフィールドを扱う必要があるかもしれないコードを、教えてくれるわけです。.. を使ったパターンは、そのままコンパイルできます。どちらの動きにするかはあなたが選べますが、Rust が代わりに推測することはありません。
直し方1:.. を付けて残りを無視する
Section titled “直し方1:.. を付けて残りを無視する”たいていはこれを選びます。一部のフィールドだけが必要なら、パターンの最後に .. を付けます。let、match、if let、関数の引数のどこでも使えますが、必ず最後に置きます。
struct Order { id: u32, item: String, quantity: u32, paid: bool,}
fn main() { let order = Order { id: 1, item: String::from("keyboard"), quantity: 2, paid: true }; let Order { item, quantity, .. } = order; // ✅ `..` が `id` と `paid` を飛ばす println!("{} x {}", quantity, item);
let orders = [ Order { id: 2, item: String::from("mouse"), quantity: 1, paid: false }, Order { id: 3, item: String::from("monitor"), quantity: 1, paid: true }, ]; for order in &orders { match order { Order { paid: true, item, .. } => println!("{} を発送します", item), Order { id, .. } => println!("注文 #{} は支払い待ちです", id), } }}実行結果:
2 x keyboard注文 #2 は支払い待ちですmonitor を発送します1つ目のアームの paid: true に注目してください。パターンの中のフィールドは、値と比べることもできます。それでも、ほかのフィールドは .. が引き受けてくれます。
直し方2:足りないフィールドの名前を書くか、_ で名前ごと無視する
Section titled “直し方2:足りないフィールドの名前を書くか、_ で名前ごと無視する”そのフィールドが本当に必要なときや、あとでフィールドが追加されたらパターンが壊れてほしいときは、これを選びます。名前付きのフィールドを持つ列挙型のバリアントに match するときも、同じエラーが出ます。
error[E0027]: pattern does not mention field `y` --> src/main.rs:9:9 |9 | Message::Move { x } => println!("move to x = {}", x), // ❌ `y` is not mentioned | ^^^^^^^^^^^^^^^^^^^ missing field `y`このエラーが出るプログラムです(コメントは「y に触れていない」という意味です)。
enum Message { Move { x: i32, y: i32 }, Quit,}
fn main() { let m = Message::Move { x: 1, y: 2 }; match m { Message::Move { x } => println!("move to x = {}", x), // ❌ `y` is not mentioned Message::Quit => println!("quit"), }}移動には座標が2つあるので、本当は両方を使うべきです。だから y の名前を書きましょう。フィールドが本当にどうでもいいときは、y: _ と書けば、名前を並べたまま、そのことをはっきり示せます。
enum Message { Move { x: i32, y: i32 }, Quit,}
fn main() { let messages = [Message::Move { x: 1, y: 2 }, Message::Move { x: 5, y: 0 }, Message::Quit]; for m in &messages { match m { Message::Move { x, y: 0 } => println!("床に沿って x = {} まで滑る", x), Message::Move { x, y } => println!("({}, {}) へ移動", x, y), // ✅ 両方のフィールド Message::Quit => println!("終了"), } }
// すべてのフィールドを名前で並べている:`Move` にフィールドを足すと、わざと壊れる if let Message::Move { x, y: _ } = &messages[0] { println!("最初の x = {}", x); }}実行結果:
(1, 2) へ移動床に沿って x = 5 まで滑る終了最初の x = 1無視するためだけにフィールドの名前を書くなら、ただの y ではなく y: _ と書きましょう。使わない y を書くと、「unused variable」(使われていない変数)という警告が出ます。
直し方3:つづりの間違ったフィールド名を直す
Section titled “直し方3:つづりの間違ったフィールド名を直す”E0027 が同じ行の E0026 と一緒に出たときは、これを選びます。たとえば、フィールドが radius のバリアントに Shape::Circle { r } と書くと、両方が出ます。r について E0026(そんなフィールドはない)、radius について E0027(触れていない)です。rustc の E0027 の help は、r の隣に radius を足すように提案しますが、それはあなたの望むことではありません。本当の直し方は、間違った名前を置き換えることです。Shape::Circle { radius } と書くか、短い変数名のままにしたいなら Shape::Circle { radius: r } と書きます。そうすれば、2つのエラーが一度に消えます。例は E0026 のページを見てください。
よく出会う場面
Section titled “よく出会う場面”構造体にフィールドを追加したあと。 Order に created_at を追加すると、すべてのフィールドを並べていたパターンが E0027 になります。これはチェックがちゃんと仕事をしている証拠です。1つずつ判断しましょう。このコードに created_at は必要でしょうか。必要なら名前を書き、いらないなら .. を付けます。
関数の引数。 fn print_order(&Order { item, quantity }: &Order) も E0027 になります。直し方:&Order { item, quantity, .. }。詳しくはlet と関数の引数でのパターンを見てください。
タプル構造体とタプルバリアント。 struct Color(u8, u8, u8); に対する Color(r) というパターンも不完全ですが、rustc はこれを E0023「this pattern has 1 field, but the corresponding tuple struct has 3 fields」(このパターンにはフィールドが1つあるが、対応するタプル構造体には3つある)として報告します。直し方の考え方は同じで、Color(r, ..) か Color(r, _, _) と書きます。
関連するエラー
Section titled “関連するエラー”- E0026:構造体やバリアントにないフィールド名:パターンの中に、存在しないフィールド名がある場合です。E0027 と一緒に表示されることがよくあります。
- E0063:フィールドが足りない:構造体を作るときの同じ考え方です。すべてのフィールドに値が必要です(または
..Default::default()を使います)。 - E0004:matchの網羅漏れ:
matchがすべてのバリアントを扱っていない場合です。E0027 はすべてのフィールドについてのエラーです。 E0023: this pattern has N fields, but the corresponding tuple struct has M fields:タプル構造体版のエラーです(上を見てください)。- コンパイルエラーの一覧:エラー解説ページの全リストです。
理解度チェック
Section titled “理解度チェック”理解度チェック
1. struct Point { x: i32, y: i32, z: i32 } があります。コンパイルできて、x だけを取り出せるパターンはどれですか?
2. Order { item, .. } と Order { item, id: _, quantity: _, paid: _ } の違いは何ですか?
3. 同じ行で、r について E0026、radius について E0027 が出ました。いちばん良い直し方はどれですか?
スコア: 0 / 3
さらに詳しく
Section titled “さらに詳しく”- E0027 — Rust error codes index(英語):このエラーの公式の説明です。
- パターン記法 — The Rust Programming Language 日本語版:構造体の分配(分解)と、「
..で値の残りの部分を無視する」方法です。 - 構造体 — Rust By Example 日本語版:
..を使った構造体のパターンの、実行できる例です。 - Patterns — The Rust Reference(英語):構造体パターンと残りパターン(rest pattern)の、正確なルールです。