Rustのエラー E0533: expected unit struct, unit variant or constant, found struct variant({ } の書き忘れ)
E0533 は、Shape::Circle のような名前を単独で書いたけれど、その場所では名前だけでは足りない、という意味のエラーです。いちばん多いのは、名前付きのフィールドを持つ列挙型のバリアント(Circle { radius: f64 })を、{ } なしで書いた場合です。match のアームでも、値を作るときでも起こります。もう少しまれなのは、決まった値しか置けない場所に関数やメソッドを書いた場合です。rustc が何を求めているのかがわかれば、どちらもすぐに直せます。このシリーズのほかのエラーは、Rustのコンパイルエラー解説を見てください。
エラーメッセージ
Section titled “エラーメッセージ”error[E0533]: expected unit struct, unit variant or constant, found struct variant `Shape::Circle` --> src/main.rs:8:9 |8 | Shape::Circle => "circle", // ❌ `Circle` has a field | ^^^^^^^^^^^^^ not a unit struct, unit variant or constant |help: the struct variant's field is being ignored |8 | Shape::Circle { radius: _ } => "circle", // ❌ `Circle` has a field | +++++++++++++「expected unit struct, unit variant or constant, found struct variant Shape::Circle」は「ユニット構造体、ユニットバリアント、定数のどれかが来るはずなのに、構造体バリアント Shape::Circle が見つかった」という意味です。
このエラーが出るのは、次のプログラムです。
enum Shape { Circle { radius: f64 }, Square { side: f64 },}
fn name(shape: &Shape) -> &'static str { match shape { Shape::Circle => "circle", // ❌ `Circle` has a field Shape::Square { .. } => "square", }}
fn main() { println!("{}", name(&Shape::Square { side: 2.0 }));}コメントは「Circle にはフィールドがある」という意味です(エラーになる例なので、コードはそのままにしています)。
エラーの意味
Section titled “エラーの意味”^^^ は Shape::Circle を指していて、見出しの行は、そこに何なら置けたのかを説明しています。名前だけのパターンは、次の3つのどれかでなければなりません。
- ユニット構造体(unit struct):
struct Empty;のようなもの - ユニットバリアント(unit variant):データを持たないバリアント。
Shape::EmptyやNoneなど - 定数(constant):
const MAX: u32 = 100;のようなもの
Shape::Circle はそのどれでもありません。これは構造体バリアント(struct variant)で、radius を持っています。Shape::Circle とだけ書くと「円」にはマッチしますが、そのフィールドについては何も言っていません。Rust は、パターンの形がバリアントの形と合っていることを求めます。help: の行(「構造体バリアントのフィールドを無視している」)が直し方を見せてくれています。波かっこを付けるのです。
E0533 にはもう1つの種類があり、expected value, found struct variant(値が来るはずなのに、構造体バリアントが見つかった)と表示されます。同じ取り違えですが、値を作るときのもので、たいてい Shape::Circle(2.0) のように丸かっこで書いてしまった場合です。
宅配便の伝票に「サイズ:S、M、L」という欄があって、そこに「特注」と書いたようなものです。特注も本当にある選択肢ですが、その隣に寸法を書き込む必要があります。
Rust がこうする理由
Section titled “Rust がこうする理由”列挙型のバリアントには3つの形があり、作るときもマッチするときも、それぞれ決まった書き方をします(列挙型はデータを持てるを見てください)。
| バリアント | 作るとき | マッチするとき |
|---|---|---|
ユニット:Empty |
Shape::Empty |
Shape::Empty |
タプル:Point(f64, f64) |
Shape::Point(1.0, 2.0) |
Shape::Point(x, y) または Shape::Point(..) |
構造体:Circle { radius: f64 } |
Shape::Circle { radius: 2.0 } |
Shape::Circle { radius } または Shape::Circle { .. } |
形を厳しく守ることで、パターンはいつもマッチする相手と同じ見た目になります。だから match を読めば、それぞれのアームがどんなデータを持っているかが正確にわかります。それに、バリアントの形が変わったとき(たとえば Empty にフィールドが増えたとき)、古い形を使っている場所がすべて指摘されるので、黙って間違った動きをすることがありません。
直し方1:パターンに { .. } かフィールドを付ける
Section titled “直し方1:パターンに { .. } かフィールドを付ける”エラーが match、if let、matches! のアームを指していて、found struct variant と言っているときは、これを選びます。フィールドが必要なければ { .. } と書き、必要なら名前を書きます。rustc の提案した { radius: _ } でも動きますが、{ .. } のほうが同じことを短く言えます。
enum Shape { Circle { radius: f64 }, Square { side: f64 }, Empty,}
fn name(shape: &Shape) -> &'static str { match shape { Shape::Circle { .. } => "円", // ✅ 「半径がいくつでも、円」 Shape::Square { .. } => "正方形", Shape::Empty => "なし", // ユニットバリアント:波かっこはいらない }}
fn area(shape: &Shape) -> f64 { match shape { Shape::Circle { radius } => 3.14 * radius * radius, // ✅ 必要なのでフィールド名を書く Shape::Square { side } => side * side, Shape::Empty => 0.0, }}
fn main() { let shapes = [Shape::Circle { radius: 1.0 }, Shape::Square { side: 3.0 }, Shape::Empty]; for shape in &shapes { println!("{}: {:.2}", name(shape), area(shape)); } let circles = shapes.iter().filter(|s| matches!(s, Shape::Circle { .. })).count(); println!("円は{}個", circles);}実行結果:
円: 3.14正方形: 9.00なし: 0.00円は1個{ .. } は、フィールドがいくつあっても、どの構造体バリアントにも使えます。タプルバリアントでは、同じことを (..) と書きます。詳しくは_ と .. で一部を無視するを見てください。
直し方2:波かっことフィールド名で値を作る
Section titled “直し方2:波かっことフィールド名で値を作る”メッセージが expected value, found struct variant のときは、これを選びます。構造体バリアントを、タプルバリアントのように(あるいはフィールドなしで)作ろうとしています。
error[E0533]: expected value, found struct variant `Shape::Circle` --> src/main.rs:8:17 |8 | let shape = Shape::Circle(2.0); // ❌ `Circle` has a named field | ^^^^^^^^^^^^^ not a value |help: you might have meant to create a new value of the struct |8 - let shape = Shape::Circle(2.0); // ❌ `Circle` has a named field8 + let shape = Shape::Circle { radius: /* value */ }; // ❌ `Circle` has a named field |help は「構造体の新しい値を作るつもりだったのかもしれない」という意味です。
このエラーが出るプログラムです(コメントは「Circle には名前付きのフィールドがある」という意味です)。
#[derive(Debug)]enum Shape { Circle { radius: f64 }, Square { side: f64 },}
fn main() { let shape = Shape::Circle(2.0); // ❌ `Circle` has a named field println!("{:?}", shape);}提案の中の /* value */ は、あなたの値を入れる場所の目印です。構造体バリアントのフィールドは、波かっこの中で名前を付けて設定します。
#[derive(Debug)]enum Shape { Circle { radius: f64 }, Square { side: f64 },}
impl Shape { // `Shape::circle(2.0)` と書きたいなら、短いコンストラクタを用意する fn circle(radius: f64) -> Shape { Shape::Circle { radius } }}
fn main() { let a = Shape::Circle { radius: 2.0 }; // ✅ 波かっことフィールド名 let b = Shape::Square { side: 1.5 }; let c = Shape::circle(0.5); println!("{:?}", a); println!("{:?}", b); println!("{:?}", c);}実行結果:
Circle { radius: 2.0 }Square { side: 1.5 }Circle { radius: 0.5 }どうしても Shape::Circle(2.0) と書きたいなら、定義をタプルバリアントの Circle(f64) に変えましょう。フィールドが1つで意味がはっきりしているなら、それも良い選択です。フィールドがいくつもあるときは、名前付きのほうがわかりやすくなります。
直し方3:関数の代わりに定数かマッチガードを使う
Section titled “直し方3:関数の代わりに定数かマッチガードを使う”メッセージが found associated function(関連関数が見つかった)のときは、これを選びます。String::len のようなメソッドでも出ます。パターンは、コンパイルのときにわかっている値でなければなりません。関数の呼び出しはそうではないので、関数の名前をパターンとして使うことはできません。
error[E0533]: expected unit struct, unit variant or constant, found associated function `Limits::max_users` --> src/main.rs:12:9 |12 | Limits::max_users => "full", // ❌ a function can't be a pattern | ^^^^^^^^^^^^^^^^^ not a unit struct, unit variant or constantこのエラーが出るプログラムです(コメントは「関数はパターンになれない」という意味です)。
struct Limits;
impl Limits { fn max_users() -> u32 { 100 }}
fn status(users: u32) -> &'static str { match users { 0 => "empty", Limits::max_users => "full", // ❌ a function can't be a pattern _ => "open", }}
fn main() { println!("{}", status(100));}値がずっと変わらないなら、const にしましょう。定数はパターンになれます。計算が必要なら、関数はそのままにして、if を使ったマッチガードで比べます。
struct Limits;
impl Limits { const MAX_USERS: u32 = 100; // 定数はパターンとして使える
fn max_rooms(premium: bool) -> u32 { if premium { 20 } else { 5 } }}
fn status(users: u32) -> &'static str { match users { 0 => "空っぽ", Limits::MAX_USERS => "満員", // ✅ 定数 _ => "受付中", }}
fn rooms_status(rooms: u32, premium: bool) -> &'static str { match rooms { n if n >= Limits::max_rooms(premium) => "これ以上部屋を増やせません", // ✅ ガードの中で呼ぶ _ => "部屋を追加できます", }}
fn main() { println!("{}", status(0)); println!("{}", status(100)); println!("{}", status(42)); println!("{}", rooms_status(5, false)); println!("{}", rooms_status(5, true));}実行結果:
空っぽ満員受付中これ以上部屋を増やせません部屋を追加できますマッチガードについては、マッチガード:if を付け足すで説明しています。
よく出会う場面
Section titled “よく出会う場面”ユニットバリアントにフィールドを追加したあと。 もともとユニットバリアントだった Status::Done を、Done { at: u64 } に変えたとします。すると、Status::Done => というアームも、let s = Status::Done; という行も、すべて E0533 になります。直し方:パターンでは Status::Done { .. } =>、作る場所では(本当の値を入れて)Status::Done { at: 0 } と書きます。
ほかの言語から来た場合。 Java や TypeScript では、値の種類だけを調べるために case Circle: と書くことがあります。Rust では Shape::Circle { .. } => と書きます。ちょっと bool が欲しいだけなら matches!(shape, Shape::Circle { .. }) です。
タプルバリアント版。 Circle(f64) のようなタプルバリアントに Shape::Circle => とだけ書いたアームは、別のコード E0532 になります。見出しは同じ「expected unit struct, unit variant or constant, found tuple variant Shape::Circle」(ただし最後が「タプルバリアントが見つかった」)です。直し方は Shape::Circle(_) か Shape::Circle(..) です。逆に、Circle { radius: f64 } に対して Shape::Circle(r) => のように、パターンで構造体バリアントに丸かっこを使うと、E0164「expected tuple struct or tuple variant, found struct variant」(タプル構造体かタプルバリアントが来るはずなのに、構造体バリアントが見つかった)になります。直し方:Shape::Circle { radius: r } =>。
関連するエラー
Section titled “関連するエラー”- E0559:バリアントにないフィールド名:波かっこは正しいけれど、中のフィールド名が間違っている場合です。
- E0026:構造体やバリアントにないフィールド名:パターンの波かっこの中に、間違ったフィールド名がある場合です。
- E0027:パターンがフィールドに触れていない:パターンの波かっこが、フィールドを書き漏らしている場合です。
..を付けましょう。 - E0004:matchの網羅漏れ:アームを直したあとも、
matchはすべてのバリアントを扱う必要があります。 E0532: expected unit struct, unit variant or constant, found tuple variant:タプルバリアント版のエラーです(上を見てください)。- コンパイルエラーの一覧:エラー解説ページの全リストです。
理解度チェック
Section titled “理解度チェック”理解度チェック
1. enum Shape { Circle { radius: f64 } } に対して、コンパイルできる match のアームはどれですか?
2. let s = Shape::Circle(2.0); で「expected value, found struct variant」が出ました。直し方はどれですか?
3. 単独で match のパターンとして使えるのはどれですか?
スコア: 0 / 3
さらに詳しく
Section titled “さらに詳しく”- E0533 — Rust error codes index(英語):このエラーの公式の説明です。
- パターン記法 — The Rust Programming Language 日本語版:enum の分配(分解)、
..で値を無視する方法、マッチガードについて。 - 列挙型 — Rust By Example 日本語版:ユニット、タプル、構造体の各バリアントへのマッチを並べて見られます。
- E0532 — Rust error codes index(英語):この間違いのタプルバリアント版の、公式のページです。
- Patterns — The Rust Reference(英語):パターンとして使えるパスと、構造体パターン・タプル構造体パターンのルールです。