コンテンツにスキップ

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のコンパイルエラー解説を見てください。

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 fields
8 + 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 は名前付きフィールドを持っている」という意味です(エラーになる例なので、コードはそのままにしています)。

^^^ はパターン 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 にはデータを持つ方法が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 なら正しいパターンです。

バリアントを名前付きフィールドに変えたあと。 わかりやすくするために、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())です。直し方はこのページと同じです。

理解度チェック

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