Ir al contenido

Error E0164 de Rust: expected tuple struct or tuple variant, found struct variant

E0164 significa: escribiste paréntesis en un patrón, como Shape::Circle(r), detrás de un nombre que no recibe valores entre paréntesis. En el Rust actual lo verás en tres situaciones: una variante de enum con campos con nombre (Circle { radius: f64 }) usada en un match como si fuera una variante de tupla, una función asociada como Celsius::new(d) usada como patrón, y una constante asociada como Volume::MAX(_) con paréntesis detrás. Cada una tiene una solución corta y clara. (Esta página forma parte de Errores del compilador de Rust explicados.)

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
|

En español: “se esperaba un tuple struct o una variante de tupla, pero se encontró la variante de struct Shape::Circle”.

Este es el programa que lo produce:

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 }));
}

El ^^^ cubre todo el patrón Shape::Circle(r), y la etiqueta dice qué esperaba Rust ahí: “a tuple struct or tuple variant” (un tuple struct o una variante de tupla). Solo esas dos cosas se escriben con paréntesis en un patrón, porque solo ellas guardan valores por posición, como Some(x) o Meters(m).

Shape::Circle es una variante de struct (struct variant). Su valor tiene nombre, radius, y los campos con nombre se emparejan con llaves: Shape::Circle { radius }.

Cuidado con el help: de este caso. Sugiere Shape::Circle { radius: _ }, que arregla el patrón pero ignora el radio. Nuestra rama usa r, así que si copias la sugerencia tal cual obtienes un error nuevo, E0425 cannot find value `r` in this scope (no se encuentra el valor r en este ámbito). Cuando necesitas el valor, dale un nombre dentro de las llaves, como en la Solución 1.

Es como un formulario con casillas con etiqueta, “Ancho: … Alto: …”, en el que escribiste “3, 4” al lado del título. Puede que los números estén bien, pero el formulario quiere cada uno en su casilla.

Un patrón tiene que parecerse al valor con el que encaja. Rust tiene dos formas de guardar datos, y cada una tiene su propio patrón (mira Los enums pueden guardar datos):

Definida como Se crea con Se empareja con
Circle(f64) (variante de tupla) Shape::Circle(1.0) Shape::Circle(r)
Circle { radius: f64 } (variante de struct) Shape::Circle { radius: 1.0 } Shape::Circle { radius }

Los campos con nombre se emparejan por nombre, no por posición, así que el orden en el patrón no importa, y añadir un campo más adelante no desplaza en silencio a los demás. Rust no deja mezclar los dos estilos, así que nunca hay dudas sobre qué valor va en cada sitio.

Además, los patrones se comprueban al compilar, así que no pueden ejecutar código. Por eso el nombre de una función seguido de (d) tampoco puede ser un patrón, aunque la función construya justo el valor que buscas. Más en Pattern matching.

Solución 1: Usa llaves con los nombres de los campos

Sección titulada «Solución 1: Usa llaves con los nombres de los campos»

Elige esta cuando el mensaje dice found struct variant, que es el E0164 más común. Escribe el nombre del campo (Rust crea una variable con ese nombre), campo: otro_nombre para elegir otro nombre, o { .. } para ignorar todos los campos:

enum Shape {
Circle { radius: f64 },
Rect { w: f64, h: f64 },
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle { radius } => 3.14 * radius * radius, // ✅ el nombre del campo entre llaves
Shape::Rect { w: width, h: height } => width * height, // ✅ campo: otro nombre
}
}
fn name(shape: &Shape) -> &'static str {
match shape {
Shape::Circle { .. } => "círculo", // ✅ "cualquier círculo"
Shape::Rect { .. } => "rectángulo",
}
}
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));
}
}

Salida:

círculo: 3.14
rectángulo: 6.00
▶ Pruébalo tú mismo

Si nombras algunos campos pero no todos, añade .. al final, como en Shape::Rect { w, .. }. Si no lo pones, obtienes E0027, y un nombre de campo mal escrito da E0026.

Solución 2: Convierte la variante en una variante de tupla

Sección titulada «Solución 2: Convierte la variante en una variante de tupla»

Elige esta cuando de verdad quieres paréntesis: la variante tiene un único valor evidente y prefieres escribir Shape::Circle(1.0) en todas partes. Cambia la definición, y el patrón Circle(r) pasa a ser correcto:

enum Shape {
Circle(f64), // ✅ ahora es una variante de tupla: un valor sin nombre
Rect { w: f64, h: f64 },
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle(r) => 3.14 * r * r, // ✅ los paréntesis encajan con una variante de tupla
Shape::Rect { w, h } => w * h,
}
}
fn main() {
let small = Shape::Circle(1.0); // también se crea con paréntesis
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));
}

Salida:

3.14 12.56 2.00
▶ Pruébalo tú mismo

Esto cambia el tipo, así que cada sitio que crea o empareja Circle también tiene que pasar a usar paréntesis. El compilador te los señala uno a uno. Para dos o más valores, los campos con nombre suelen ser más claros.

Solución 3: Empareja el propio tuple struct y llama a las funciones en una guarda

Sección titulada «Solución 3: Empareja el propio tuple struct y llama a las funciones en una guarda»

Elige esta cuando el mensaje dice found associated function (se encontró una función asociada) y la etiqueta dice `fn` calls are not allowed in patterns (no se permiten llamadas a fn en los patrones). Escribiste un constructor como Celsius::new(d) donde Rust necesita un patrón:

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

El programa que lo produce:

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 es un tuple struct, así que el patrón es el nombre del propio struct: Celsius(d). Todo lo que necesite una llamada a una función o a un método va en una guarda (match guard), el if ... que va detrás del patrón:

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 => "calor", // ✅ el propio tuple struct, más una guarda
Celsius(_) => "fresco",
}
}
fn describe(t: &Celsius) -> &'static str {
match t {
t if t.is_freezing() => "bajo cero", // ✅ los métodos van en una guarda
_ => "sobre cero",
}
}
fn main() {
println!("{}", feels(Celsius::new(30.0)));
println!("{}", feels(Celsius::new(12.5)));
let Celsius(d) = Celsius::new(-3.0); // ✅ también funciona con `let`
println!("{} grados", d);
println!("{}", describe(&Celsius::new(-3.0)));
}

Salida:

calor
fresco
-3 grados
bajo cero
▶ Pruébalo tú mismo

Si el campo del struct es privado (porque vive en otro módulo), no puedes escribir Celsius(d) fuera de ese módulo. En ese caso usa un getter en una guarda, como t if t.degrees() > 25.0. Mira Guardas: añadir un if.

Solución 4: Quita los paréntesis detrás de una constante

Sección titulada «Solución 4: Quita los paréntesis detrás de una constante»

Elige esta cuando el mensaje dice found associated constant (se encontró una constante asociada). Una constante ya es un patrón completo. Encaja con un único valor exacto, así que no hay nada que poner entre paréntesis:

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

El programa que lo produce:

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));
}

Escribe la constante sola:

struct Volume;
impl Volume {
const MAX: u8 = 10;
}
fn label(level: u8) -> &'static str {
match level {
0 => "silencio",
Volume::MAX => "al máximo", // ✅ una constante, sola
1..=3 => "bajo",
_ => "normal",
}
}
fn main() {
for level in [0, 2, 7, 10, u8::MAX] {
println!("{}: {}", level, label(level));
}
}

Salida:

0: silencio
2: bajo
7: normal
10: al máximo
255: normal
▶ Pruébalo tú mismo

Lo mismo vale para las constantes de la biblioteca estándar: u32::MAX(_) es E0164, y u32::MAX es un patrón válido.

Después de pasar una variante a campos con nombre. Convertiste Move(i32, i32) en Move { x: i32, y: i32 } para que se entienda mejor. Ahora cada rama antigua Command::Move(x, y) => da E0164. Solución: Command::Move { x, y } =>.

Emparejar con una función “parser”. Algo como match input { Version::parse(v) => ... }, con la esperanza de que la función se ejecute durante el match. Solución: llámala primero y luego haz match con el resultado: match Version::parse(input) { Some(v) => ..., None => ... }.

Las funciones sueltas, los structs normales y las variantes unitarias dan E0532. El mismo error de paréntesis se muestra como E0532 cuando el nombre no se alcanza a través de un tipo: una función suelta (Some(limit()), expected a pattern, found a function call), un struct con campos con nombre (let Point(x, y) = p;, found struct `Point` ) o una variante unitaria (Status::Active()). Las soluciones son las mismas que en esta página.

Comprueba lo aprendido

1. Para enum Shape { Circle { radius: f64 } }, ¿qué rama usa bien el radio?

2. Celsius::new(d) => ... da "fn calls are not allowed in patterns". Celsius es struct Celsius(f64);. ¿Qué patrón funciona?

3. ¿Cómo emparejas la constante asociada Volume::MAX?

Puntuación: 0 / 3