コンテンツにスキップ

Rustのエラー E0027: pattern does not mention field x(パターンのフィールド漏れ)

E0027 は、let Order { item, quantity } = order; のようなパターンで構造体や列挙型のバリアントを分解しようとしたけれど、すべてのフィールドに触れていない、という意味のエラーです。Rust では、構造体のパターンはすべてのフィールドを扱わなければなりません。名前を書くか、.. で「残りは全部」と言うかのどちらかです。これはいちばん親切なエラーの1つです。rustc が正確な直し方を表示してくれて、それはほとんどの場合、点2つだけです。このシリーズのほかのエラーは、Rustのコンパイルエラー解説を見てください。

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 に触れていない」という意味です(エラーになる例なので、コードはそのままにしています)。

見出しの行には、パターンで書き漏らしたフィールド(id と paid)が並んでいます。^^^ はパターン全体に引かれています。問題は1つの間違った単語ではなく、何かが足りないことだからです。

続いて rustc は、3つの help: を出します。どれも正しい直し方ですが、意味はそれぞれ違います。

  • include the missing fields(足りないフィールドをパターンに含める):名前を書きます。id と paid という変数も手に入ります。
  • explicitly ignore them(はっきり無視する):id: _, paid: _ と書きます。変数は作られませんが、すべてのフィールドを名前で並べたことになります。
  • always ignore missing fields here(ここでは足りないフィールドをいつも無視する):.. と書きます。「ほかのフィールドがあっても、気にしない」という意味です。

入り口のチェックリストに「すべての欄にチェックを入れるか、『その他:飛ばす』にチェックを入れてください」と書いてあるようなものです。空欄のまま出すことはできません。

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 のページを見てください。

構造体にフィールドを追加したあと。 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, _, _) と書きます。

  • E0026:構造体やバリアントにないフィールド名:パターンの中に、存在しないフィールド名がある場合です。E0027 と一緒に表示されることがよくあります。
  • E0063:フィールドが足りない:構造体を作るときの同じ考え方です。すべてのフィールドに値が必要です(または ..Default::default() を使います)。
  • E0004:matchの網羅漏れ:match がすべてのバリアントを扱っていない場合です。E0027 はすべてのフィールドについてのエラーです。
  • E0023: this pattern has N fields, but the corresponding tuple struct has M fields:タプル構造体版のエラーです(上を見てください)。
  • コンパイルエラーの一覧:エラー解説ページの全リストです。

理解度チェック

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