コンテンツにスキップ

Rustのエラー E0559: variant has no field named x(バリアントにないフィールド名)

E0559 は、Enum::Variant { field: value } で列挙型の値を作るときに書いたフィールドのどれかが、そのバリアントに存在しない、という意味のエラーです。構造体で同じ間違いをしたときの E0560 の、列挙型版です。たいていは、短すぎるかつづりの違うフィールド名、別のバリアントのフィールド、あるいはかっこ ( ) で作るバリアントに波かっこ { } を使った、のどれかです。直すのは、ほとんどの場合たった1語です。このシリーズのほかのエラーは、Rustのコンパイルエラー解説を見てください。

error[E0559]: variant `Shape::Circle` has no field named `r`
--> src/main.rs:8:33
|
8 | let shape = Shape::Circle { r: 2.0 }; // ❌ the field is called `radius`
| ^ `Shape::Circle` does not have this field
|
= note: available fields are: `radius`

「variant Shape::Circle has no field named r」は「バリアント Shape::Circle に r という名前のフィールドはない」という意味です。note は「使えるフィールドは radius」と教えてくれています。

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

#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
}
fn main() {
let shape = Shape::Circle { r: 2.0 }; // ❌ the field is called `radius`
println!("{:?}", shape);
}

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

見出しには、バリアント(Shape::Circle)と自分が書いたフィールド(r)が出ています。^ は、波かっこの中のそのフィールドを指しています。Rust は Circle { radius: f64 } という定義を見て、r というフィールドを見つけられなかったのです。

列挙型(enum)のバリアントは、それぞれ自分だけのフィールドの一覧を持っています。Shape::Circle には radius、Shape::Rectangle には width と height があります。同じ列挙型の中でも、フィールドを共有することはありません。

矢印の下には、次のヒントのどれかが出ます。まずはこれを読みましょう。たいてい答えが書いてあります。

  • note: available fields are: `radius`(使えるフィールドは radius):近い名前がありません。このバリアントにあって、まだ値を入れていないフィールドの一覧です。
  • help: a field with a similar name exists(似た名前のフィールドがある):key を kye と書いたようなタイプミスです。rustc が直した行を見せてくれます。
  • help: `Message::Write` is a tuple variant, use the appropriate syntax(Message::Write はタプルバリアントなので、それに合った書き方をしてください):そのバリアントのフィールドには名前がないので、{ } ではなく ( ) が必要です。
  • note: all struct fields are already assigned(フィールドはすべて代入済み):本当のフィールドは全部埋めていて、このフィールドは余分です。

ピザを注文するときに、メニューには「生地のサイズ」しかないのに「大きい生地」と書くようなものです。お店の人には言いたいことがわかりますが、注文用紙にはその名前の欄がありません。

Circle { radius: f64 } のように名前付きのフィールドを持つバリアントは、列挙型の中にある小さな構造体のように働きます。それを作るとき、Rust はちょうどそのフィールドが過不足なく書かれているかをチェックします。足りないものも、余分なものも、つづりの違うものもあってはいけません。詳しくは列挙型はデータを持てるを見てください。

これがいちばん効いてくるのは、あとでその列挙型を match するときです。Shape::Circle { radius } => ... というアームがうまく動くのは、どの Circle も本当に radius を持っているからです。もし Rust が Shape::Circle { r: 2.0 } を通してしまったら、その保証がなくなります。タイプミスをコンパイル時に見つけることで、プログラムの中のどの Circle も欠けのない状態に保たれるのです。

直し方1:バリアントの本当のフィールド名を使う

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

rustc が available fields are や a field with a similar name exists と言っているときは、これを選びます。ヒントにある名前を使いましょう。フィールド名は大文字と小文字を区別し、snake_case で書くので、Radius と radius は別の名前です。

タイプミスなら「似た名前」のヒントが出ます。

error[E0559]: variant `Event::KeyPress` has no field named `kye`
--> src/main.rs:8:31
|
8 | let e = Event::KeyPress { kye: 'a' };
| ^^^ unknown field
|
help: a field with a similar name exists
|
8 - let e = Event::KeyPress { kye: 'a' };
8 + let e = Event::KeyPress { key: 'a' };
|

unknown field は「知らないフィールド」という意味です。

r のような短い名前は radius とかけ離れすぎていて提案が出ないので、代わりにフィールドの一覧が表示されます。どちらの場合も、バリアントが定義しているフィールドを書きましょう。

#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
}
#[derive(Debug)]
enum Event {
Click { x: i32, y: i32 },
KeyPress { key: char },
}
fn main() {
let shapes = [
Shape::Circle { radius: 2.0 }, // ✅ 本当のフィールド名
Shape::Rectangle { width: 3.0, height: 4.0 },
];
for shape in &shapes {
println!("{:?}", shape);
}
let events = [Event::KeyPress { key: 'a' }, Event::Click { x: 10, y: 20 }];
println!("{:?}", events);
}

実行結果:

Circle { radius: 2.0 }
Rectangle { width: 3.0, height: 4.0 }
[KeyPress { key: 'a' }, Click { x: 10, y: 20 }]
▶ 実際に試してみよう

フィールド初期化省略記法(field init shorthand)にも気をつけましょう。Shape::Circle { r } は Shape::Circle { r: r } という意味なので、同じ E0559 になります。変数の名前が r なら、フィールドを省略せずに Shape::Circle { radius: r } と書きます。または、変数の名前を radius に変えて Shape::Circle { radius } と書きます。

直し方2:タプルバリアントにはかっこを使う

Section titled “直し方2:タプルバリアントにはかっこを使う”

rustc が is a tuple variant, use the appropriate syntax と言っているときは、これを選びます。Write(String) のようなバリアントにはフィールドがありますが、そのフィールドには名前がありません。だから、波かっこの中にどんな名前を書いても間違いになります。

error[E0559]: variant `Message::Write` has no field named `text`
--> src/main.rs:8:30
|
4 | Write(String),
| ----- `Message::Write` defined here
...
8 | let m = Message::Write { text: String::from("hi") };
| ^^^^ field does not exist
|
help: `Message::Write` is a tuple variant, use the appropriate syntax
|
8 - let m = Message::Write { text: String::from("hi") };
8 + let m = Message::Write(/* String */);
|

defined here は「ここで定義されている」、field does not exist は「フィールドが存在しない」という意味です。

提案の中の /* String */ は仮置きの印なので、そこに自分の値を入れます。タプルバリアントは、定義と同じ順番で、かっこを使って作りましょう。

#[derive(Debug)]
enum Message {
Move { x: i32, y: i32 }, // 名前付きのフィールド:{ } を使う
Write(String), // 名前のないフィールド:( ) を使う
Color(u8, u8, u8),
}
fn main() {
let messages = vec![
Message::Move { x: 1, y: 2 },
Message::Write(String::from("hi")), // ✅ かっこ
Message::Color(255, 128, 0),
];
for m in &messages {
match m {
Message::Move { x, y } => println!("({}, {}) へ移動", x, y),
Message::Write(text) => println!("書き込み: {}", text),
Message::Color(r, g, b) => println!("色: {} {} {}", r, g, b),
}
}
}

実行結果:

(1, 2) へ移動
書き込み: hi
色: 255 128 0
▶ 実際に試してみよう

フィールドに名前を付けたいなら、定義を Write { text: String } に変えます。そうすれば Message::Write { text: ... } と書けます。逆の取り違え、つまり名前付きのフィールドを持つバリアントにかっこを使う Shape::Circle(2.0) は、別のエラーになります。E0533「expected value, found struct variant」(値が必要なのに、構造体形式のバリアントが見つかった)です。

直し方3:正しいバリアントを選ぶ、またはバリアントを変える

Section titled “直し方3:正しいバリアントを選ぶ、またはバリアントを変える”

書いたフィールドは存在するけれど、別のバリアントのものだったときは、これを選びます。ここでは、radius は Square ではなく Circle のフィールドです。

error[E0559]: variant `Shape::Square` has no field named `radius`
--> src/main.rs:8:29
|
8 | let s = Shape::Square { radius: 2.0 };
| ^^^^^^ `Shape::Square` does not have this field
|
= note: available fields are: `side`

`Shape::Square` does not have this field は「Shape::Square にこのフィールドはない」という意味です。

どちらのつもりだったのか、考えてみましょう。円が欲しかったのなら Shape::Circle { radius: 2.0 } を使います。正方形が欲しかったのなら、そのフィールドを使って Shape::Square { side: 2.0 } と書きます。

note: all struct fields are already assigned と出たら、そのバリアントはもう全部埋まっていて、書いたフィールドは余分です。消しましょう。あるいは、コードで本当に必要なら、バリアントの定義に追加します。

#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Square { side: f64 },
}
#[derive(Debug)]
enum Message {
Move { x: i32, y: i32, z: i32 }, // コードで必要なので `z` を追加した
}
fn main() {
let a = Shape::Circle { radius: 2.0 }; // 円には半径がある
let b = Shape::Square { side: 2.0 }; // 正方形には辺がある
println!("{:?} と {:?}", a, b);
let m = Message::Move { x: 1, y: 2, z: 3 };
println!("{:?}", m);
}

実行結果:

Circle { radius: 2.0 } と Square { side: 2.0 }
Move { x: 1, y: 2, z: 3 }
▶ 実際に試してみよう

バリアントにフィールドを追加したら、そのバリアントを作っているすべての場所でも、そのフィールドに値を入れる必要があります。rustc が E0063「missing field」(フィールドが足りない)で1か所ずつ教えてくれます。

Self:: を使うコンストラクタのメソッド。 impl Shape の中で fn circle(r: f64) -> Shape { Self::Circle { r } } と書くと、省略記法のせいで r について E0559 になります。直し方:Self::Circle { radius: r }。詳しくは列挙型にもメソッドを持たせられるを見てください。

フィールドの名前を変えたあと。 列挙型の Circle { r } を Circle { radius } に変えると、古い Shape::Circle { r: ... } がすべて available fields are: `radius` 付きの E0559 になります。プロジェクト全体で古い名前を検索して、1つずつ直しましょう。

match のパターンの中。 Shape::Circle { r } => ... のように、パターンに間違ったフィールド名を書くのも同じ間違いですが、rustc は別のコードを使います。E0026「variant Shape::Circle does not have a field named r」(バリアント Shape::Circle に r という名前のフィールドはない)と help: `Shape::Circle` has a field named `radius`(Shape::Circle には radius という名前のフィールドがある)、さらに E0027「pattern does not mention field radius」(パターンにフィールド radius が書かれていない)が出ます。直し方:Shape::Circle { radius } => ... と書くか、短い名前のままにしたいなら Shape::Circle { radius: r } => ... と書きます。詳しくはパターンマッチングを見てください。

理解度チェック

1. enum Message { Write(String) } のとき、Message::Write { text: s } はどう書き直せばいいですか?

2. let r = 2.0; があって Shape::Circle { r } と書きましたが、フィールドは radius です。どう直しますか?

3. Shape::Square { radius: 2.0 } が E0559 になり、注記には side しか出ていません。何が起きていますか?

スコア: 0 / 3