Zum Inhalt springen

Rust-Fehler E0164: expected tuple struct or tuple variant, found struct variant

E0164 bedeutet: Du hast in einem Muster runde Klammern geschrieben, etwa Shape::Circle(r), hinter einem Namen, der keine Werte in runden Klammern annimmt. Im heutigen Rust begegnet er dir in drei Situationen: eine Enum-Variante mit benannten Feldern (Circle { radius: f64 }), die du abgleichst, als wäre sie eine Tupel-Variante; eine assoziierte Funktion wie Celsius::new(d), die du als Muster benutzt; und eine assoziierte Konstante wie Volume::MAX(_) mit Klammern dahinter. Für jeden Fall gibt es eine kurze, klare Lösung. (Diese Seite gehört zur Reihe Rust-Compilerfehler einfach erklärt.)

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` hat benannte Felder
| ^^^^^^^^^^^^^^^^ 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` hat benannte Felder
8 + Shape::Circle { radius: _ } => 3.14 * r * r, // ❌ `Circle` hat benannte Felder
|

Auf Deutsch: „Tupel-Struct oder Tupel-Variante erwartet, Struct-Variante Shape::Circle gefunden.“ Die Hilfe sagt: „Das Feld der Struct-Variante wird ignoriert.“

Dieses Programm erzeugt den Fehler:

enum Shape {
Circle { radius: f64 },
Square { side: f64 },
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle(r) => 3.14 * r * r, // ❌ `Circle` hat benannte Felder
Shape::Square { side } => side * side,
}
}
fn main() {
println!("{}", area(&Shape::Square { side: 2.0 }));
}

Die ^^^ decken das ganze Muster Shape::Circle(r) ab, und das Label sagt, was Rust dort erwartet hat: „a tuple struct or tuple variant“ (ein Tupel-Struct oder eine Tupel-Variante). Nur diese beiden Arten schreibst du in einem Muster mit runden Klammern, denn nur sie halten Werte nach Position, wie Some(x) oder Meters(m).

Shape::Circle ist eine Struct-Variante. Ihr Wert hat einen Namen, radius, und benannte Felder gleichst du mit geschweiften Klammern ab: Shape::Circle { radius }.

Vorsicht mit dem help: hier. Es schlägt Shape::Circle { radius: _ } vor. Das repariert zwar das Muster, ignoriert aber den Radius. Unser Zweig benutzt r, also ergibt der unveränderte Vorschlag einen neuen Fehler: E0425, cannot find value `r` in this scope. Wenn du den Wert brauchst, gib ihm in den geschweiften Klammern einen Namen, wie in Lösung 1.

Das ist wie ein Formular mit beschrifteten Feldern, „Breite: … Höhe: …“, und du schreibst „3, 4“ neben die Überschrift. Die Zahlen stimmen vielleicht, aber das Formular will jede in ihrem beschrifteten Feld.

Ein Muster muss aussehen wie der Wert, den es abgleicht. Rust hat zwei Arten, Daten zu halten, und jede hat ihr eigenes Muster (siehe Enums können Daten enthalten):

Definiert als Erzeugt mit Abgeglichen mit
Circle(f64) (Tupel-Variante) Shape::Circle(1.0) Shape::Circle(r)
Circle { radius: f64 } (Struct-Variante) Shape::Circle { radius: 1.0 } Shape::Circle { radius }

Benannte Felder werden über den Namen abgeglichen, nicht über die Position. Die Reihenfolge im Muster spielt also keine Rolle, und ein später hinzugefügtes Feld verschiebt die anderen nicht heimlich. Beide Stile zu mischen ist verboten, darum gibt es nie Zweifel, welcher Wert wohin gehört.

Muster werden außerdem zur Compilezeit geprüft, also können sie keinen Code ausführen. Deshalb kann auch ein Funktionsname mit (d) dahinter kein Muster sein, selbst wenn die Funktion genau den Wert baut, den du abgleichst. Mehr dazu unter Pattern Matching.

Lösung 1: Geschweifte Klammern mit den Feldnamen benutzen

Abschnitt betitelt „Lösung 1: Geschweifte Klammern mit den Feldnamen benutzen“

Nimm diese Lösung, wenn die Meldung found struct variant sagt. Das ist das häufigste E0164. Schreib den Feldnamen (Rust legt dann eine Variable mit diesem Namen an), feld: neuer_name für einen anderen Namen, oder { .. }, um alle Felder zu ignorieren:

enum Shape {
Circle { radius: f64 },
Rect { w: f64, h: f64 },
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle { radius } => 3.14 * radius * radius, // ✅ Feldname in geschweiften Klammern
Shape::Rect { w: width, h: height } => width * height, // ✅ feld: neuer Name
}
}
fn name(shape: &Shape) -> &'static str {
match shape {
Shape::Circle { .. } => "Kreis", // ✅ „irgendein Kreis“
Shape::Rect { .. } => "Rechteck",
}
}
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));
}
}

Ausgabe:

Kreis: 3.14
Rechteck: 6.00
▶ Selbst ausprobieren

Nennst du nur einige Felder, schreib .. ans Ende, etwa Shape::Rect { w, .. }. Ohne das bekommst du E0027, und ein falsch geschriebener Feldname ergibt E0026.

Lösung 2: Die Variante zu einer Tupel-Variante machen

Abschnitt betitelt „Lösung 2: Die Variante zu einer Tupel-Variante machen“

Nimm diese Lösung, wenn du wirklich runde Klammern willst: Die Variante hat einen einzigen, offensichtlichen Wert, und du schreibst lieber überall Shape::Circle(1.0). Ändere die Definition, dann ist das Muster Circle(r) richtig:

enum Shape {
Circle(f64), // ✅ jetzt eine Tupel-Variante: ein Wert ohne Namen
Rect { w: f64, h: f64 },
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle(r) => 3.14 * r * r, // ✅ runde Klammern passen zu einer Tupel-Variante
Shape::Rect { w, h } => w * h,
}
}
fn main() {
let small = Shape::Circle(1.0); // auch beim Erzeugen mit runden Klammern
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));
}

Ausgabe:

3.14 12.56 2.00
▶ Selbst ausprobieren

Damit änderst du den Typ. Jede Stelle, die Circle erzeugt oder abgleicht, muss also ebenfalls auf runde Klammern umstellen. Der Compiler zeigt dir jede einzelne. Bei zwei oder mehr Werten sind benannte Felder meist klarer.

Lösung 3: Das Tupel-Struct selbst abgleichen und Funktionen im Guard aufrufen

Abschnitt betitelt „Lösung 3: Das Tupel-Struct selbst abgleichen und Funktionen im Guard aufrufen“

Nimm diese Lösung, wenn die Meldung found associated function sagt und das Label `fn` calls are not allowed in patterns (fn-Aufrufe sind in Mustern nicht erlaubt). Du hast einen Konstruktor wie Celsius::new(d) geschrieben, wo Rust ein Muster braucht:

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` ist eine Funktion, kein Muster
| ^^^^^^^^^^^^^^^ `fn` calls are not allowed in patterns

Das Programm dazu:

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` ist eine Funktion, kein Muster
_ => "cool",
}
}
fn main() {
println!("{}", feels(Celsius::new(30.0)));
}

Celsius ist ein Tupel-Struct, also ist das Muster der Name des Structs selbst: Celsius(d). Alles, was einen Funktions- oder Methodenaufruf braucht, gehört in einen Match Guard (if ... hinter dem Muster):

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 => "warm", // ✅ das Tupel-Struct selbst, plus ein Guard
Celsius(_) => "kühl",
}
}
fn describe(t: &Celsius) -> &'static str {
match t {
t if t.is_freezing() => "Frost", // ✅ Methoden gehören in einen Guard
_ => "kein Frost",
}
}
fn main() {
println!("{}", feels(Celsius::new(30.0)));
println!("{}", feels(Celsius::new(12.5)));
let Celsius(d) = Celsius::new(-3.0); // ✅ funktioniert auch mit `let`
println!("{} Grad", d);
println!("{}", describe(&Celsius::new(-3.0)));
}

Ausgabe:

warm
kühl
-3 Grad
Frost
▶ Selbst ausprobieren

Ist das Feld des Structs privat (weil es in einem anderen Modul liegt), kannst du außerhalb dieses Moduls nicht Celsius(d) schreiben. Nimm dann einen Getter in einem Guard, etwa t if t.degrees() > 25.0. Siehe Match Guards: ein zusätzliches if.

Lösung 4: Die Klammern hinter einer Konstante weglassen

Abschnitt betitelt „Lösung 4: Die Klammern hinter einer Konstante weglassen“

Nimm diese Lösung, wenn die Meldung found associated constant sagt. Eine Konstante ist schon ein vollständiges Muster. Sie passt auf genau einen Wert, also gibt es nichts, was in Klammern gehört:

error[E0164]: expected tuple struct or tuple variant, found associated constant `Volume::MAX`
--> src/main.rs:10:9
|
10 | Volume::MAX(_) => "loudest", // ❌ eine Konstante nimmt keine ()
| ^^^^^^^^^^^^^^ not a tuple struct or tuple variant

Das Programm dazu:

struct Volume;
impl Volume {
const MAX: u8 = 10;
}
fn label(level: u8) -> &'static str {
match level {
0 => "muted",
Volume::MAX(_) => "loudest", // ❌ eine Konstante nimmt keine ()
_ => "normal",
}
}
fn main() {
println!("{}", label(10));
}

Schreib die Konstante allein hin:

struct Volume;
impl Volume {
const MAX: u8 = 10;
}
fn label(level: u8) -> &'static str {
match level {
0 => "stumm",
Volume::MAX => "am lautesten", // ✅ eine Konstante, allein
1..=3 => "leise",
_ => "normal",
}
}
fn main() {
for level in [0, 2, 7, 10, u8::MAX] {
println!("{}: {}", level, label(level));
}
}

Ausgabe:

0: stumm
2: leise
7: normal
10: am lautesten
255: normal
▶ Selbst ausprobieren

Dasselbe gilt für Konstanten aus der Standardbibliothek: u32::MAX(_) ist E0164, u32::MAX ist ein gültiges Muster.

Nachdem du eine Variante auf benannte Felder umgestellt hast. Du hast Move(i32, i32) der Klarheit halber zu Move { x: i32, y: i32 } gemacht. Jetzt ergibt jeder alte Command::Move(x, y) =>-Zweig E0164. Lösung: Command::Move { x, y } =>.

Abgleich mit einer „Parser“-Funktion. Zum Beispiel match input { Version::parse(v) => ... }, in der Hoffnung, dass die Funktion beim Abgleichen läuft. Lösung: Ruf sie zuerst auf und gleiche dann das Ergebnis ab: match Version::parse(input) { Some(v) => ..., None => ... }.

Freie Funktionen, normale Structs und Unit-Varianten ergeben stattdessen E0532. Derselbe Klammerfehler wird als E0532 gemeldet, wenn der Name nicht über einen Typ erreicht wird: eine normale Funktion (Some(limit()), expected a pattern, found a function call), ein Struct mit benannten Feldern (let Point(x, y) = p;, found struct `Point` ) oder eine Unit-Variante (Status::Active()). Die Lösungen sind dieselben wie auf dieser Seite.

Kurzer Check

1. Welcher Zweig benutzt den Radius bei enum Shape { Circle { radius: f64 } } richtig?

2. Celsius::new(d) => ... ergibt „fn calls are not allowed in patterns“. Celsius ist struct Celsius(f64);. Welches Muster funktioniert?

3. Wie gleichst du die assoziierte Konstante Volume::MAX ab?

Punkte: 0 / 3