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.)
El mensaje de error
Sección titulada «El mensaje de error»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 |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 }));}Qué significa
Sección titulada «Qué significa»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.
Por qué Rust hace esto
Sección titulada «Por qué Rust hace esto»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.
Cómo solucionarlo
Sección titulada «Cómo solucionarlo»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.14rectángulo: 6.00Si 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.00Esto 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 patternsEl 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:
calorfresco-3 gradosbajo ceroSi 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 variantEl 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: silencio2: bajo7: normal10: al máximo255: normalLo mismo vale para las constantes de la biblioteca estándar: u32::MAX(_) es E0164, y u32::MAX es un patrón válido.
Dónde lo verás normalmente
Sección titulada «Dónde lo verás normalmente»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.
Errores relacionados
Sección titulada «Errores relacionados»- E0532: expected tuple struct or tuple variant, found unit variant or struct: la misma confusión con structs normales, variantes unitarias y funciones sueltas, y el caso contrario (una variante de tupla escrita sin paréntesis).
- E0533: expected unit struct, unit variant or constant, found struct variant: una variante de struct escrita sin llaves, como
Shape::Circle =>. - E0026: struct or variant does not have a field named x: las llaves están bien, pero un nombre de campo dentro está mal.
- E0027: pattern does not mention field x: llaves que dejan campos fuera; añade
... - E0425: cannot find value in this scope: lo que obtienes si copias la sugerencia
{ radius: _ }pero sigues usandor. - Todos los errores del compilador explicados
Comprueba lo que aprendiste
Sección titulada «Comprueba lo que aprendiste»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
Para leer más
Sección titulada «Para leer más»- E0164 — Rust error codes index (en inglés): la explicación oficial, con el ejemplo de la constante asociada.
- Pattern Syntax — El libro de Rust (en inglés): desestructurar enums con llaves o con paréntesis, ignorar campos con
..y las guardas. También existe una traducción al español de la comunidad del libro. - Destructuring enums — Rust by Example (en inglés): variantes de tupla y de struct en un mismo
match. - Patterns — The Rust Reference (en inglés): qué rutas pueden aparecer en los patrones de tuple struct y de struct.