Ir al contenido

Error E0533 de Rust: expected unit struct, unit variant or constant, found struct variant

E0533 significa: escribiste un nombre como Shape::Circle solo, pero ese nombre necesita algo más que su nombre para usarse ahí. Casi siempre es una variante de enum con campos con nombre (Circle { radius: f64 }) escrita sin sus { }, ya sea en un brazo de match o al crear un valor. Menos a menudo es una función o un método escrito donde solo puede ir un valor fijo. Las dos cosas se arreglan rápido en cuanto sabes qué te pide rustc. (Esta página forma parte de Errores del compilador de Rust explicados.)

error[E0533]: expected unit struct, unit variant or constant, found struct variant `Shape::Circle`
--> src/main.rs:8:9
|
8 | Shape::Circle => "circle", // ❌ `Circle` has a field
| ^^^^^^^^^^^^^ not a unit struct, unit variant or constant
|
help: the struct variant's field is being ignored
|
8 | Shape::Circle { radius: _ } => "circle", // ❌ `Circle` has a field
| +++++++++++++

“Expected unit struct, unit variant or constant, found struct variant” quiere decir “se esperaba un unit struct, una variante unitaria o una constante, y se encontró una variante de struct”. El help te avisa de que el campo de la variante se está ignorando, y te muestra cómo escribirlo con llaves.

Este es el programa que lo produce:

enum Shape {
Circle { radius: f64 },
Square { side: f64 },
}
fn name(shape: &Shape) -> &'static str {
match shape {
Shape::Circle => "circle", // ❌ `Circle` has a field
Shape::Square { .. } => "square",
}
}
fn main() {
println!("{}", name(&Shape::Square { side: 2.0 }));
}

El ^^^ señala Shape::Circle, y el titular explica qué se permitía ahí: un patrón que es solo un nombre tiene que ser una de estas tres cosas:

  • un unit struct (struct sin campos), como struct Empty;
  • una variante unitaria, una variante sin datos, como Shape::Empty o None
  • una constante, como const MAX: u32 = 100;

Shape::Circle no es ninguna de ellas. Es una variante de struct: lleva un radius. Un Shape::Circle a secas coincidiría con “un círculo”, pero no diría nada de su campo, y Rust quiere que la forma del patrón coincida con la forma de la variante. La línea help: te enseña la solución: añade las llaves.

La segunda clase de E0533 dice expected value, found struct variant (se esperaba un valor, se encontró una variante de struct). Es la misma confusión, pero al crear un valor, normalmente escrito con paréntesis, como Shape::Circle(2.0).

Es como un formulario de paquetería con una casilla que dice “Tamaño: S, M o L”, y tú escribiste “A medida”. “A medida” es una opción real, pero necesita que rellenes las medidas al lado.

Las variantes de un enum tienen tres formas, y cada una se escribe a su manera, tanto al crearla como al hacer match con ella (mira Los enums pueden guardar datos):

Variante Crearla Hacer match con ella
Unitaria: Empty Shape::Empty Shape::Empty
De tupla: Point(f64, f64) Shape::Point(1.0, 2.0) Shape::Point(x, y) o Shape::Point(..)
De struct: Circle { radius: f64 } Shape::Circle { radius: 2.0 } Shape::Circle { radius } o Shape::Circle { .. }

Mantener estas formas estrictas hace que un patrón siempre se parezca a lo que compara, así que puedes leer un match y saber exactamente qué datos tiene cada brazo. También significa que, cuando una variante cambia de forma, por ejemplo cuando Empty gana un campo, cada sitio que usa la forma antigua queda señalado en lugar de hacer algo equivocado sin avisar.

Solución 1: Añade { .. } o los campos al patrón

Sección titulada «Solución 1: Añade { .. } o los campos al patrón»

Elige esta cuando el error señala un brazo de match, if let o matches! y dice found struct variant. Escribe { .. } si no necesitas los campos, o nómbralos si los necesitas. La sugerencia de rustc, { radius: _ }, también funciona, y { .. } es la forma más corta de decir lo mismo.

enum Shape {
Circle { radius: f64 },
Square { side: f64 },
Empty,
}
fn name(shape: &Shape) -> &'static str {
match shape {
Shape::Circle { .. } => "círculo", // ✅ "un círculo, tenga el radio que tenga"
Shape::Square { .. } => "cuadrado",
Shape::Empty => "nada", // una variante unitaria: no necesita llaves
}
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle { radius } => 3.14 * radius * radius, // ✅ campos nombrados porque los necesitamos
Shape::Square { side } => side * side,
Shape::Empty => 0.0,
}
}
fn main() {
let shapes = [Shape::Circle { radius: 1.0 }, Shape::Square { side: 3.0 }, Shape::Empty];
for shape in &shapes {
println!("{}: {:.2}", name(shape), area(shape));
}
let circles = shapes.iter().filter(|s| matches!(s, Shape::Circle { .. })).count();
println!("{} círculo(s)", circles);
}

Salida:

círculo: 3.14
cuadrado: 9.00
nada: 0.00
1 círculo(s)
▶ Pruébalo tú mismo

{ .. } funciona con cualquier variante de struct, tenga los campos que tenga. Para las variantes de tupla, la misma idea se escribe (..). Mira Ignorar partes con _ y ...

Solución 2: Crea el valor con llaves y nombres de campos

Sección titulada «Solución 2: Crea el valor con llaves y nombres de campos»

Elige esta cuando el mensaje dice expected value, found struct variant. Estás creando una variante de struct como si fuera una variante de tupla (o sin ningún campo):

error[E0533]: expected value, found struct variant `Shape::Circle`
--> src/main.rs:8:17
|
8 | let shape = Shape::Circle(2.0); // ❌ `Circle` has a named field
| ^^^^^^^^^^^^^ not a value
|
help: you might have meant to create a new value of the struct
|
8 - let shape = Shape::Circle(2.0); // ❌ `Circle` has a named field
8 + let shape = Shape::Circle { radius: /* value */ }; // ❌ `Circle` has a named field
|

La etiqueta not a value significa “no es un valor”, y el help dice que quizá querías crear un valor nuevo del struct, con la línea ya escrita con llaves.

El programa que hay detrás:

#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Square { side: f64 },
}
fn main() {
let shape = Shape::Circle(2.0); // ❌ `Circle` has a named field
println!("{:?}", shape);
}

El /* value */ de la sugerencia es un hueco para tu valor. Los campos de una variante de struct se asignan por su nombre, dentro de llaves:

#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Square { side: f64 },
}
impl Shape {
// un constructor corto, si quieres escribir `Shape::circle(2.0)`
fn circle(radius: f64) -> Shape {
Shape::Circle { radius }
}
}
fn main() {
let a = Shape::Circle { radius: 2.0 }; // ✅ llaves y el nombre del campo
let b = Shape::Square { side: 1.5 };
let c = Shape::circle(0.5);
println!("{:?}", a);
println!("{:?}", b);
println!("{:?}", c);
}

Salida:

Circle { radius: 2.0 }
Square { side: 1.5 }
Circle { radius: 0.5 }
▶ Pruébalo tú mismo

Si prefieres escribir Shape::Circle(2.0), cambia la definición a una variante de tupla: Circle(f64). Es una buena opción para un solo campo evidente; los campos con nombre son más claros cuando hay varios.

Solución 3: Usa una constante o una guarda en lugar de una función

Sección titulada «Solución 3: Usa una constante o una guarda en lugar de una función»

Elige esta cuando el mensaje dice found associated function (se encontró una función asociada). También aparece con métodos, como String::len. Un patrón tiene que ser un valor que se conoce al compilar. Una llamada a una función no lo es, así que el nombre de una función no puede usarse como patrón:

error[E0533]: expected unit struct, unit variant or constant, found associated function `Limits::max_users`
--> src/main.rs:12:9
|
12 | Limits::max_users => "full", // ❌ a function can't be a pattern
| ^^^^^^^^^^^^^^^^^ not a unit struct, unit variant or constant

Rust esperaba un unit struct, una variante unitaria o una constante, y encontró la función asociada Limits::max_users.

El programa que hay detrás:

struct Limits;
impl Limits {
fn max_users() -> u32 {
100
}
}
fn status(users: u32) -> &'static str {
match users {
0 => "empty",
Limits::max_users => "full", // ❌ a function can't be a pattern
_ => "open",
}
}
fn main() {
println!("{}", status(100));
}

Si el valor nunca cambia, conviértelo en un const. Las constantes sí pueden ser patrones. Si hay que calcularlo, quédate con la función y compara en una guarda (match guard) con if:

struct Limits;
impl Limits {
const MAX_USERS: u32 = 100; // una constante se puede usar como patrón
fn max_rooms(premium: bool) -> u32 {
if premium { 20 } else { 5 }
}
}
fn status(users: u32) -> &'static str {
match users {
0 => "vacío",
Limits::MAX_USERS => "lleno", // ✅ una constante
_ => "abierto",
}
}
fn rooms_status(rooms: u32, premium: bool) -> &'static str {
match rooms {
n if n >= Limits::max_rooms(premium) => "no caben más salas", // ✅ la llamas en una guarda
_ => "puedes añadir una sala",
}
}
fn main() {
println!("{}", status(0));
println!("{}", status(100));
println!("{}", status(42));
println!("{}", rooms_status(5, false));
println!("{}", rooms_status(5, true));
}

Salida:

vacío
lleno
abierto
no caben más salas
puedes añadir una sala
▶ Pruébalo tú mismo

Las guardas se explican en Guardas: añadir un if.

Después de que una variante unitaria gane campos. Status::Done era una variante unitaria, y la cambiaste a Done { at: u64 }. Ahora cada brazo Status::Done => y cada let s = Status::Done; da E0533. Solución: Status::Done { .. } => en los patrones, y Status::Done { at: 0 } (con un valor real) donde lo creas.

Si vienes de otro lenguaje. En Java o TypeScript quizá escribirías case Circle: para comprobar solo de qué clase es un valor. En Rust, escribe Shape::Circle { .. } =>, o matches!(shape, Shape::Circle { .. }) para obtener un bool rápido.

La versión para variantes de tupla. Con una variante de tupla como Circle(f64), un brazo Shape::Circle => a secas da otro código, E0532, con el mismo titular: “expected unit struct, unit variant or constant, found tuple variant Shape::Circle” (se encontró una variante de tupla). La solución es Shape::Circle(_) o Shape::Circle(..). Y poner paréntesis a una variante de struct en un patrón, como Shape::Circle(r) => para Circle { radius: f64 }, da E0164, “expected tuple struct or tuple variant, found struct variant” (se esperaba un tuple struct o una variante de tupla, se encontró una variante de struct). Solución: Shape::Circle { radius: r } =>.

Comprueba lo aprendido

1. Con enum Shape { Circle { radius: f64 } }, ¿qué brazo de match compila?

2. let s = Shape::Circle(2.0); da "expected value, found struct variant". ¿Cuál es la solución?

3. ¿Cuál de estos se puede usar solo como patrón de un match?

Puntuación: 0 / 3