Rustのエラー E0164: expected tuple struct or tuple variant, found struct variant(パターンの ( ) の間違い)
E0164 は、丸かっこで値を受け取らない名前のあとに、パターンで Shape::Circle(r) のような丸かっこを書いたという意味のエラーです。今の Rust でこのエラーに出会うのは、3つの場面です。名前付きフィールドを持つ列挙型のバリアント(Circle { radius: f64 })をタプルバリアントのようにマッチしたとき、Celsius::new(d) のような関連関数をパターンとして使ったとき、そして Volume::MAX(_) のように関連定数のあとに丸かっこを付けたときです。どれも短く、はっきりした直し方があります。このシリーズのほかのエラーは、Rustのコンパイルエラー解説を見てください。
エラーメッセージ
Section titled “エラーメッセージ”error[E0164]: expected tuple struct or tuple variant, found struct variant `Shape::Circle` --> src/main.rs:8:9 |8 | Shape::Circle(r) => 3.14 * r * r, // ❌ `Circle` has named fields | ^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant |help: the struct variant's field is being ignored |8 - Shape::Circle(r) => 3.14 * r * r, // ❌ `Circle` has named fields8 + Shape::Circle { radius: _ } => 3.14 * r * r, // ❌ `Circle` has named fields |「expected tuple struct or tuple variant, found struct variant」は「タプル構造体かタプルバリアントが来るはずなのに、構造体バリアントが見つかった」という意味です。
このエラーが出るのは、次のプログラムです。
enum Shape { Circle { radius: f64 }, Square { side: f64 },}
fn area(shape: &Shape) -> f64 { match shape { Shape::Circle(r) => 3.14 * r * r, // ❌ `Circle` has named fields Shape::Square { side } => side * side, }}
fn main() { println!("{}", area(&Shape::Square { side: 2.0 }));}コメントは「Circle は名前付きフィールドを持っている」という意味です(エラーになる例なので、コードはそのままにしています)。
エラーの意味
Section titled “エラーの意味”^^^ はパターン Shape::Circle(r) 全体を指していて、ラベルは Rust がそこに何を期待していたかを伝えています。「a tuple struct or tuple variant」(タプル構造体かタプルバリアント)です。パターンで丸かっこを使って書けるのは、この2種類だけです。Some(x) や Meters(m) のように、値を位置で持っているのはこの2つだけだからです。
Shape::Circle は構造体バリアントです。その値には radius という名前があり、名前付きフィールドは波かっこでマッチします。Shape::Circle { radius } です。
ここでの help: には注意してください。提案されている Shape::Circle { radius: _ } でパターンは直りますが、半径は無視されます。このアームは r を使っているので、提案をそのままコピーすると、新しいエラー E0425 cannot find value `r` in this scope(このスコープに値 r が見つからない)になります。値が必要なときは、直し方1のように、波かっこの中で名前を付けましょう。
「幅:… 高さ:…」と欄に名前の付いた用紙に、タイトルの横に「3, 4」と書いてしまったようなものです。数字は合っているかもしれませんが、用紙はそれぞれの数字を名前の付いた欄に書いてほしいのです。
Rust がこうする理由
Section titled “Rust がこうする理由”パターンは、マッチする値と同じ見た目でなければいけません。Rust にはデータを持つ方法が2つあり、それぞれに専用のパターンがあります(列挙型はデータを持てるを見てください)。
| 定義 | 作るとき | マッチするとき |
|---|---|---|
Circle(f64)(タプルバリアント) |
Shape::Circle(1.0) |
Shape::Circle(r) |
Circle { radius: f64 }(構造体バリアント) |
Shape::Circle { radius: 1.0 } |
Shape::Circle { radius } |
名前付きフィールドは位置ではなく名前でマッチするので、パターンの中の順番は関係ありませんし、あとでフィールドを足しても、ほかのフィールドが黙ってずれることはありません。2つの書き方を混ぜることは認められていないので、どの値がどこに入るのか迷うこともありません。
また、パターンはコンパイル時にチェックされるので、コードを実行することはできません。だから、関数の名前に (d) を付けたものもパターンにはなれません。その関数が、マッチしたい値をそのまま作る関数だったとしても同じです。くわしくはパターンマッチングを見てください。
直し方1:フィールド名と波かっこを使う
Section titled “直し方1:フィールド名と波かっこを使う”メッセージが found struct variant のときは、これを選びます。いちばんよくある E0164 です。フィールド名を書く(Rust がその名前の変数を作ります)か、別の名前にしたいなら フィールド: 新しい名前、全部のフィールドを無視するなら { .. } と書きます。
enum Shape { Circle { radius: f64 }, Rect { w: f64, h: f64 },}
fn area(shape: &Shape) -> f64 { match shape { Shape::Circle { radius } => 3.14 * radius * radius, // ✅ 波かっこの中にフィールド名 Shape::Rect { w: width, h: height } => width * height, // ✅ フィールド: 新しい名前 }}
fn name(shape: &Shape) -> &'static str { match shape { Shape::Circle { .. } => "円", // ✅「どんな円でも」 Shape::Rect { .. } => "長方形", }}
fn main() { let shapes = [Shape::Circle { radius: 1.0 }, Shape::Rect { w: 2.0, h: 3.0 }]; for shape in &shapes { println!("{}: {:.2}", name(shape), area(shape)); }}実行結果:
円: 3.14長方形: 6.00一部のフィールドだけを書くときは、Shape::Rect { w, .. } のように最後に .. を付けます。付け忘れると E0027 に、フィールド名のつづりを間違えると E0026 になります。
直し方2:バリアントをタプルバリアントに変える
Section titled “直し方2:バリアントをタプルバリアントに変える”本当に丸かっこを使いたいときは、これを選びます。バリアントの値が1つで意味がはっきりしていて、どこでも Shape::Circle(1.0) と書きたい場合です。定義を変えれば、Circle(r) のパターンが正しくなります。
enum Shape { Circle(f64), // ✅ タプルバリアントになった:名前のない値が1つ Rect { w: f64, h: f64 },}
fn area(shape: &Shape) -> f64 { match shape { Shape::Circle(r) => 3.14 * r * r, // ✅ タプルバリアントには丸かっこが合う Shape::Rect { w, h } => w * h, }}
fn main() { let small = Shape::Circle(1.0); // 作るときも丸かっこ let big = Shape::Circle(2.0); let door = Shape::Rect { w: 1.0, h: 2.0 }; println!("{:.2} {:.2} {:.2}", area(&small), area(&big), area(&door));}実行結果:
3.14 12.56 2.00これは型そのものを変えるので、Circle を作ったりマッチしたりしている場所も、すべて丸かっこに変える必要があります。コンパイラがその場所を1つずつ教えてくれます。値が2つ以上あるなら、たいていは名前付きフィールドのほうがわかりやすいです。
直し方3:タプル構造体そのものでマッチし、関数はガードで呼ぶ
Section titled “直し方3:タプル構造体そのものでマッチし、関数はガードで呼ぶ”メッセージが found associated function(関連関数が見つかった)で、ラベルが `fn` calls are not allowed in patterns(パターンの中で fn を呼ぶことはできない)のときは、これを選びます。Rust がパターンを求めている場所に、Celsius::new(d) のようなコンストラクタを書いてしまった場合です。
error[E0164]: expected tuple struct or tuple variant, found associated function `Celsius::new` --> src/main.rs:11:9 |11 | Celsius::new(d) if d > 25.0 => "warm", // ❌ `new` is a function, not a pattern | ^^^^^^^^^^^^^^^ `fn` calls are not allowed in patternsエラーになるプログラムはこちらです(コメントは「new は関数で、パターンではない」という意味です)。
struct Celsius(f64);
impl Celsius { fn new(degrees: f64) -> Celsius { Celsius(degrees) }}
fn feels(t: Celsius) -> &'static str { match t { Celsius::new(d) if d > 25.0 => "warm", // ❌ `new` is a function, not a pattern _ => "cool", }}
fn main() { println!("{}", feels(Celsius::new(30.0)));}Celsius はタプル構造体なので、パターンは構造体自身の名前を使った Celsius(d) です。関数やメソッドを呼ぶ必要があるものは、すべてマッチガード(パターンのあとの if ...)に入れます。
struct Celsius(f64);
impl Celsius { fn new(degrees: f64) -> Celsius { Celsius(degrees) }
fn is_freezing(&self) -> bool { self.0 <= 0.0 }}
fn feels(t: Celsius) -> &'static str { match t { Celsius(d) if d > 25.0 => "暖かい", // ✅ タプル構造体そのものと、ガード Celsius(_) => "涼しい", }}
fn describe(t: &Celsius) -> &'static str { match t { t if t.is_freezing() => "氷点下", // ✅ メソッドはガードの中で呼ぶ _ => "氷点下ではない", }}
fn main() { println!("{}", feels(Celsius::new(30.0))); println!("{}", feels(Celsius::new(12.5))); let Celsius(d) = Celsius::new(-3.0); // ✅ `let` でも使える println!("{} 度", d); println!("{}", describe(&Celsius::new(-3.0)));}実行結果:
暖かい涼しい-3 度氷点下構造体のフィールドが非公開(別のモジュールにある)なら、そのモジュールの外では Celsius(d) と書けません。その場合は、t if t.degrees() > 25.0 のように、ガードの中でゲッターを使います。マッチガード:if を付け足すを見てください。
直し方4:定数のあとの丸かっこを消す
Section titled “直し方4:定数のあとの丸かっこを消す”メッセージが found associated constant(関連定数が見つかった)のときは、これを選びます。定数はそれだけで完全なパターンです。ちょうど1つの値にマッチするので、丸かっこの中に入れるものはありません。
error[E0164]: expected tuple struct or tuple variant, found associated constant `Volume::MAX` --> src/main.rs:10:9 |10 | Volume::MAX(_) => "loudest", // ❌ a constant takes no () | ^^^^^^^^^^^^^^ not a tuple struct or tuple variantエラーになるプログラムはこちらです(コメントは「定数に () は付けない」という意味です)。
struct Volume;
impl Volume { const MAX: u8 = 10;}
fn label(level: u8) -> &'static str { match level { 0 => "muted", Volume::MAX(_) => "loudest", // ❌ a constant takes no () _ => "normal", }}
fn main() { println!("{}", label(10));}定数だけを書きます。
struct Volume;
impl Volume { const MAX: u8 = 10;}
fn label(level: u8) -> &'static str { match level { 0 => "ミュート", Volume::MAX => "最大", // ✅ 定数だけを書く 1..=3 => "小さめ", _ => "ふつう", }}
fn main() { for level in [0, 2, 7, 10, u8::MAX] { println!("{}: {}", level, label(level)); }}実行結果:
0: ミュート2: 小さめ7: ふつう10: 最大255: ふつう標準ライブラリの定数も同じです。u32::MAX(_) は E0164 になり、u32::MAX なら正しいパターンです。
よく出会う場面
Section titled “よく出会う場面”バリアントを名前付きフィールドに変えたあと。 わかりやすくするために、Move(i32, i32) を Move { x: i32, y: i32 } に変えました。すると、古い Command::Move(x, y) => のアームがすべて E0164 になります。直し方:Command::Move { x, y } =>。
「パーサー」関数でマッチしようとしたとき。 マッチの途中で関数が実行されることを期待して、match input { Version::parse(v) => ... } のように書く場合です。直し方:先に関数を呼んでから、その結果でマッチします。match Version::parse(input) { Some(v) => ..., None => ... } です。
ふつうの関数、ふつうの構造体、ユニットバリアントでは E0532 になる。 型を通さずにたどり着く名前のときは、同じ丸かっこの間違いが E0532 として表示されます。ふつうの関数(Some(limit())、expected a pattern, found a function call)、名前付きフィールドを持つ構造体(let Point(x, y) = p;、found struct `Point` )、ユニットバリアント(Status::Active())です。直し方はこのページと同じです。
関連するエラー
Section titled “関連するエラー”- E0532: expected tuple struct or tuple variant, found unit variant or struct:ふつうの構造体、ユニットバリアント、ふつうの関数での同じ取り違えと、その逆(タプルバリアントに丸かっこを付け忘れた)です。
- E0533: expected unit struct, unit variant or constant, found struct variant:
Shape::Circle =>のように、構造体バリアントに波かっこをまったく書かなかった。 - E0026: struct or variant does not have a field named x:波かっこは正しいけれど、中のフィールド名が間違っている。
- E0027: pattern does not mention field x:波かっこの中でフィールドが足りない。
..を付けます。 - E0425: cannot find value in this scope:
{ radius: _ }の提案をコピーしたのに、まだrを使っているときに出ます。 - コンパイルエラーの一覧:エラー解説ページの全リストです。
理解度チェック
Section titled “理解度チェック”理解度チェック
1. enum Shape { Circle { radius: f64 } } で、半径を正しく使っているアームはどれですか?
2. Celsius::new(d) => ... と書いたら「fn calls are not allowed in patterns」と言われました。Celsius は struct Celsius(f64); です。正しいパターンはどれですか?
3. 関連定数 Volume::MAX にマッチするには、どう書きますか?
スコア: 0 / 3
さらに詳しく
Section titled “さらに詳しく”- E0164 — Rust error codes index(英語):このエラーの公式の説明です。関連定数の例が載っています。
- パターン記法 — The Rust Programming Language 日本語版:列挙型を波かっこや丸かっこで分解する方法、
..でフィールドを無視する方法、マッチガードです。 - 列挙型 — Rust By Example 日本語版:タプルバリアントと構造体バリアントのマッチを並べて見られます。
- Patterns — The Rust Reference(英語):タプル構造体パターンや構造体パターンに、どんなパスを書けるかのルールです。