Salta ai contenuti

Errore Rust E0533: expected unit struct, unit variant or constant, found struct variant

E0533 significa: hai scritto da solo un nome come Shape::Circle, ma in quel punto quel nome ha bisogno di qualcosa in più. Quasi sempre è una variante di enum con campi nominati (Circle { radius: f64 }) scritta senza le sue { }, in un ramo di match o quando crei un valore. Più di rado è una funzione o un metodo scritto dove può stare solo un valore fisso. In entrambi i casi la correzione è veloce, una volta capito che cosa chiede rustc. (Questa pagina fa parte di Errori del compilatore Rust spiegati.)

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
| +++++++++++++

Il compilatore dice: qui si aspettava una unit struct, una variante senza dati o una costante, e invece ha trovato una variante con campi. Questo è il programma che produce l’errore:

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

Il ^^^ indica Shape::Circle, e la prima riga spiega che cosa era ammesso lì: un pattern fatto solo di un nome deve essere una di queste tre cose:

  • una unit struct, come struct Empty;
  • una variante unit, cioè senza dati, come Shape::Empty o None
  • una costante, come const MAX: u32 = 100;

Shape::Circle non è nessuna delle tre. È una variante struct: porta con sé un radius. Un Shape::Circle nudo corrisponderebbe a «un cerchio» senza dire niente del suo campo, e Rust vuole che la forma del pattern corrisponda alla forma della variante. La riga help: ti mostra la correzione: aggiungi le graffe.

Il secondo tipo di E0533 dice expected value, found struct variant (atteso un valore, trovata una variante struct). È la stessa confusione, ma quando crei un valore, di solito scritto con le tonde come Shape::Circle(2.0).

È come un modulo per spedire un pacco con una casella «Taglia: S, M o L», dove tu hai scritto «Su misura». «Su misura» è un’opzione vera, ma accanto ci vanno scritte le misure.

Le varianti di un enum hanno tre forme, e ognuna si scrive a modo suo, sia quando la crei sia quando la confronti (vedi Enum in Rust):

Variante Crearla Confrontarla
Unit: Empty Shape::Empty Shape::Empty
Tupla: Point(f64, f64) Shape::Point(1.0, 2.0) Shape::Point(x, y) o Shape::Point(..)
Struct: Circle { radius: f64 } Shape::Circle { radius: 2.0 } Shape::Circle { radius } o Shape::Circle { .. }

Tenere le forme rigide significa che un pattern somiglia sempre alla cosa che confronta, quindi leggendo un match sai esattamente quali dati ha ogni ramo. Significa anche che, quando una variante cambia forma, per esempio quando Empty riceve un campo, ogni punto che usa la vecchia forma viene segnalato invece di fare in silenzio la cosa sbagliata.

Scegli questa quando l’errore indica un ramo di match, if let o matches! e dice found struct variant. Scrivi { .. } se i campi non ti servono, oppure nominali se ti servono. Anche il suggerimento di rustc { radius: _ } funziona, e { .. } è il modo più breve per dire la stessa cosa.

enum Shape {
Circle { radius: f64 },
Square { side: f64 },
Empty,
}
fn name(shape: &Shape) -> &'static str {
match shape {
Shape::Circle { .. } => "cerchio", // ✅ «un cerchio, qualunque sia il raggio»
Shape::Square { .. } => "quadrato",
Shape::Empty => "niente", // una variante unit: niente graffe
}
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle { radius } => 3.14 * radius * radius, // ✅ campi nominati perché ci servono
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!("cerchi: {}", circles);
}

Output:

cerchio: 3.14
quadrato: 9.00
niente: 0.00
cerchi: 1
▶ Provalo tu

{ .. } funziona con ogni variante struct, qualunque sia il numero di campi. Per le varianti tupla la stessa idea si scrive (..). Vedi Pattern matching in Rust.

Soluzione 2: crea il valore con graffe e nomi dei campi

Sezione intitolata “Soluzione 2: crea il valore con graffe e nomi dei campi”

Scegli questa quando il messaggio dice expected value, found struct variant. Stai creando una variante struct come se fosse una variante tupla (o senza nessun 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
|

Il programma che lo produce:

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

Il /* value */ nel suggerimento è un segnaposto per il tuo valore. I campi di una variante struct si impostano per nome, dentro le graffe:

#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Square { side: f64 },
}
impl Shape {
// un costruttore corto, se vuoi scrivere `Shape::circle(2.0)`
fn circle(radius: f64) -> Shape {
Shape::Circle { radius }
}
}
fn main() {
let a = Shape::Circle { radius: 2.0 }; // ✅ graffe e nome del campo
let b = Shape::Square { side: 1.5 };
let c = Shape::circle(0.5);
println!("{:?}", a);
println!("{:?}", b);
println!("{:?}", c);
}

Output:

Circle { radius: 2.0 }
Square { side: 1.5 }
Circle { radius: 0.5 }
▶ Provalo tu

Se preferisci scrivere Shape::Circle(2.0), cambia la definizione in una variante tupla: Circle(f64). È una buona scelta per un solo campo ovvio; i campi con nome sono più chiari quando sono parecchi.

Soluzione 3: usa una costante o una match guard al posto di una funzione

Sezione intitolata “Soluzione 3: usa una costante o una match guard al posto di una funzione”

Scegli questa quando il messaggio dice found associated function. Compare anche con i metodi, come String::len. Un pattern deve essere un valore noto in fase di compilazione. Una chiamata di funzione non lo è, quindi il nome di una funzione non può fare da pattern:

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

Il programma che lo produce:

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

Se il valore non cambia mai, rendilo una const. Le costanti possono fare da pattern. Se va calcolato, tieni la funzione e confronta in una match guard con if:

struct Limits;
impl Limits {
const MAX_USERS: u32 = 100; // una costante si può usare come pattern
fn max_rooms(premium: bool) -> u32 {
if premium { 20 } else { 5 }
}
}
fn status(users: u32) -> &'static str {
match users {
0 => "vuoto",
Limits::MAX_USERS => "pieno", // ✅ una costante
_ => "aperto",
}
}
fn rooms_status(rooms: u32, premium: bool) -> &'static str {
match rooms {
n if n >= Limits::max_rooms(premium) => "niente più stanze", // ✅ chiamala in una guard
_ => "puoi aggiungere una stanza",
}
}
fn main() {
println!("{}", status(0));
println!("{}", status(100));
println!("{}", status(42));
println!("{}", rooms_status(5, false));
println!("{}", rooms_status(5, true));
}

Output:

vuoto
pieno
aperto
niente più stanze
puoi aggiungere una stanza
▶ Provalo tu

Le match guard sono spiegate in Pattern matching in Rust.

Dopo che una variante unit riceve dei campi. Status::Done era una variante unit, e l’hai cambiata in Done { at: u64 }. Ogni ramo Status::Done => e ogni let s = Status::Done; ora danno E0533. Correzione: Status::Done { .. } => nei pattern, Status::Done { at: 0 } (con un valore vero) dove lo crei.

Se arrivi da un altro linguaggio. In Java o TypeScript potresti scrivere case Circle: per controllare solo il tipo di un valore. In Rust scrivi Shape::Circle { .. } =>, oppure matches!(shape, Shape::Circle { .. }) per ottenere al volo un bool.

La versione con le varianti tupla. Per una variante tupla come Circle(f64), un ramo Shape::Circle => nudo dà un codice diverso, E0532, con la stessa prima riga «expected unit struct, unit variant or constant, found tuple variant Shape::Circle». La correzione è Shape::Circle(_) oppure Shape::Circle(..). E le tonde su una variante struct in un pattern, come Shape::Circle(r) => per Circle { radius: f64 }, danno E0164, «expected tuple struct or tuple variant, found struct variant». Correzione: Shape::Circle { radius: r } =>.

Verifica veloce

1. Con enum Shape { Circle { radius: f64 } }, quale ramo di match compila?

2. let s = Shape::Circle(2.0); dà "expected value, found struct variant". Qual è la correzione?

3. Quale di questi si può usare da solo come pattern di un match?

Punteggio: 0 / 3