コンテンツにスキップ

Rustのエラー E0026: struct or variant does not have a field named x(パターンのフィールド名の間違い)

E0026 は、Shape::Circle { r } のようなパターンで構造体や列挙型のバリアントを分解しようとしたけれど、書いたフィールド名の1つが存在しない、という意味のエラーです。値を作るときの同じ間違いを捕まえる E0560 や E0559 の、パターン版だと考えてください。たいてい rustc が help: の行で正しい名前を教えてくれるので、直すのは1単語だけで済むことがほとんどです。このシリーズのほかのエラーは、Rustのコンパイルエラー解説を見てください。

error[E0026]: variant `Shape::Circle` does not have a field named `r`
--> src/main.rs:8:25
|
8 | Shape::Circle { r } => 3.14 * r * r, // ❌ the field is called `radius`
| ^
| |
| variant `Shape::Circle` does not have this field
| help: `Shape::Circle` has a field named `radius`

「variant Shape::Circle does not have a field named r」は「バリアント Shape::Circle には r という名前のフィールドがない」という意味です。

このエラーが出るのは、次のプログラムです。

enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle { r } => 3.14 * r * r, // ❌ the field is called `radius`
Shape::Rectangle { width, height } => width * height,
}
}
fn main() {
println!("{}", area(&Shape::Circle { radius: 1.0 }));
}

コメントは「フィールドの名前は radius」という意味です(エラーになる例なので、コードはそのままにしています)。

同じ行で、もう1つのエラー E0027「pattern does not mention field radius」(パターンがフィールド radius に触れていない)も表示されます。これは同じ間違いを反対側から見たものです。Rust は、書かれたのに存在しないフィールド(r)と、存在するのに書かれていないフィールド(radius)の両方を見つけたのです。名前を直せば、2つのエラーはどちらも消えます。

見出しの行には、マッチしようとしている構造体またはバリアント(Shape::Circle)と、あなたが書いたフィールド名(r)が出ています。^ は、パターンの波かっこの中のその名前を指しています。

パターンの { } の中にある名前はフィールド名で、自由に選べる新しい変数名ではありません。Shape::Circle { r } は Shape::Circle { r: r } の省略形で、「r という名前のフィールドを取り出して、r という変数に入れる」という意味になります。Circle には r というフィールドがないので、Rust はそこで止まります。

矢印の下に、rustc は次のどれかのヒントを出します。

  • help: `Shape::Circle` has a field named `radius`(Shape::Circle には radius というフィールドがある):書かれていないフィールドがちょうど1つなので、rustc はそれのつもりだったのだろうと推測しています。
  • help: a field with a similar name exists(似た名前のフィールドがある):name を nmae と書いたようなタイプミスです。rustc は直した行を見せてくれます。
  • ヒントなし:rustc が推測できなかった場合です。構造体や列挙型の定義を見て、本当の名前を確かめましょう。

図書館で「フィクションっぽい棚の本をください」と頼むようなものです。司書さんは、あなたがどこかの棚の本が欲しいことはわかっています。でも、行けるのは本当にある棚だけです。

Shape::Circle { radius } のようなパターンは、「値が Circle だったら、その radius をください」という約束です。Rust はコンパイルのときに、この約束を定義と照らし合わせて確かめます。だから、パターンが存在しないデータを求めることは絶対にありません。詳しくはタプルと構造体の分解を見てください。

このチェックがない言語では、ないキーを読むと undefined や null が返ってきて、バグはずっとあとになって、タイプミスから遠く離れた場所で表に出てきます。Rust では、タイプミスがコンパイラを通り抜けることはできません。誰かがフィールドの名前を変えたときにも守ってくれます。古い名前を使っているパターンはすべて E0026 で光るので、どれも黙って忘れられることがありません。

直し方1:本当のフィールド名を使う

Section titled “直し方1:本当のフィールド名を使う”

たいていはこれを選びます。help: の行に出ている名前を使うか、定義を見て確かめましょう。フィールド名は大文字と小文字を区別し、snake_case で書きます。

タイプミスの場合は、「似た名前」のヒントと、直した行が表示されます。

error[E0026]: struct `User` does not have a field named `nmae`
--> src/main.rs:8:16
|
8 | let User { nmae, age } = user; // ❌ typo: the field is `name`
| ^^^^ struct `User` does not have this field
|
help: a field with a similar name exists
|
8 - let User { nmae, age } = user; // ❌ typo: the field is `name`
8 + let User { name, age } = user; // ❌ typo: the field is `name`
|

- の行が元の行、+ の行が rustc の提案する直した行です(コメントは「タイプミス:フィールドは name」という意味です)。

このエラーが出るプログラムです。

struct User {
name: String,
age: u32,
}
fn main() {
let user = User { name: String::from("Ferris"), age: 7 };
let User { nmae, age } = user; // ❌ typo: the field is `name`
println!("{} is {} years old", nmae, age);
}

フィールド名を定義のとおりに書きましょう。そうすれば省略形がそのまま使えて、フィールドと同じ名前の変数が手に入ります。

struct User {
name: String,
age: u32,
}
enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle { radius } => 3.14 * radius * radius, // ✅ 本当のフィールド名
Shape::Rectangle { width, height } => width * height,
}
}
fn main() {
let shapes = [
Shape::Circle { radius: 2.0 },
Shape::Rectangle { width: 3.0, height: 4.0 },
];
for shape in &shapes {
println!("面積: {:.2}", area(shape));
}
let user = User { name: String::from("Ferris"), age: 7 };
let User { name, age } = user; // ✅ `nmae` ではなく `name`
println!("{}は{}歳です", name, age);
}

実行結果:

面積: 12.56
面積: 12.00
Ferrisは7歳です
▶ 実際に試してみよう

直し方2:field: name で自分の変数名を使う

Section titled “直し方2:field: name で自分の変数名を使う”

r という短い名前が気に入っていて、変数をその名前にしたいだけなら、これを選びます。本当のフィールド名、コロン、変数名の順に書きます。Shape::Circle { radius: r } です。「radius フィールドを取り出して、r と呼ぶ」と読みましょう。

enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle { radius: r } => 3.14 * r * r, // ✅ フィールドは `radius`、変数は `r`
Shape::Rectangle { width: w, height: h } => w * h,
}
}
fn main() {
let small = Shape::Circle { radius: 1.0 };
let wide = Shape::Rectangle { width: 10.0, height: 2.5 };
println!("小さい円: {:.2}", area(&small));
println!("横長の長方形: {:.2}", area(&wide));
}

実行結果:

小さい円: 3.14
横長の長方形: 25.00
▶ 実際に試してみよう

この書き方は、フィールド名がすでにある変数とぶつかってしまうときや、フィールド名が長いときにも便利です。

直し方3:正しいバリアントにマッチしているか確かめる

Section titled “直し方3:正しいバリアントにマッチしているか確かめる”

書いたフィールドは実在するけれど、別のバリアントのものだった、というときはこれを選びます。列挙型のバリアントは、それぞれ自分のフィールドを持っています。ここでは x は Click のフィールドなのに、アームは KeyPress にマッチしようとしています。

error[E0026]: variant `Event::KeyPress` does not have a field named `x`
--> src/main.rs:9:27
|
9 | Event::KeyPress { x, .. } => format!("key at {}", x), // ❌ `x` belongs to `Click`
| ^
| |
| variant `Event::KeyPress` does not have this field
| help: `Event::KeyPress` has a field named `key`

このエラーが出るプログラムです(コメントは「x は Click のもの」という意味です)。

enum Event {
Click { x: i32, y: i32 },
KeyPress { key: char },
}
fn describe(event: &Event) -> String {
match event {
Event::Click { x, y } => format!("click at ({}, {})", x, y),
Event::KeyPress { x, .. } => format!("key at {}", x), // ❌ `x` belongs to `Click`
}
}
fn main() {
println!("{}", describe(&Event::KeyPress { key: 'a' }));
}

rustc の推測(key)は「書かれていない唯一のフィールド」というだけなので、そのまま信じないようにしましょう。このアームで何をしたいのかを考えます。キーを押すことに位置はないので、ここでは KeyPress が本当に持っているフィールドを使うのが正しい直し方です。

enum Event {
Click { x: i32, y: i32 },
KeyPress { key: char },
}
fn describe(event: &Event) -> String {
match event {
Event::Click { x, y } => format!("({}, {}) をクリック", x, y),
Event::KeyPress { key } => format!("キー '{}' が押されました", key), // ✅ KeyPress が持っているのは `key`
}
}
fn main() {
let events = [Event::Click { x: 10, y: 20 }, Event::KeyPress { key: 'a' }];
for event in &events {
println!("{}", describe(event));
}
}

実行結果:

(10, 20) をクリック
キー 'a' が押されました
▶ 実際に試してみよう

キーを押したときにも本当に位置が必要なら、バリアントのほうにフィールドを追加します。KeyPress { key: char, x: i32, y: i32 } です。そうすると、KeyPress を作っているすべての場所で、そのフィールドも埋める必要があります(rustc がそれぞれの場所を E0063 で指してくれます)。

フィールドの名前を変えたあと。 列挙型の r を radius に変えたら、Shape::Circle { r } => ... というアームがすべて E0026 になった、という場合です。プロジェクト全体で古い名前を検索して、パターンを1つずつ直しましょう。古い変数名のままにしたいなら radius: r と書きます。

if let や let の中。 if let Some(User { nmae, .. }) = find_user() でも同じエラーになります。ここで .. を足しても直りません。.. は書かなかったフィールドを飛ばすだけで、書いた名前はやはりすべて存在している必要があるからです。直し方:User { name, .. }。

タプル構造体やタプルバリアントに波かっこを使った場合。 struct Point(i32, i32); には名前付きのフィールドがないので、Point { x, y } というパターンは合いません。rustc はこれを別のコード E0769「tuple variant Point written as struct variant」(タプルバリアント Point が構造体バリアントとして書かれている)で報告し、Point(x, y) を提案します。詳しくはデータを持つenumの分解を見てください。

理解度チェック

1. enum Shape { Circle { radius: f64 } } に対して、パターン Shape::Circle { r } は何を求めていますか?

2. radius フィールドを r という変数に入れたいとき、使えるパターンはどれですか?

3. フィールドの名前が name のとき、User { nmae, .. } はコンパイルできますか?

スコア: 0 / 3