Errore Rust E0532: expected unit struct, unit variant or constant, found tuple variant
E0532 significa: la forma del tuo pattern non corrisponde alla forma della cosa che hai nominato. Il caso classico è un ramo di match come Shape::Circle => per una variante che contiene dati, Circle(f64). Rust vuole le tonde: Shape::Circle(_). Lo sbaglio opposto ha lo stesso codice, con l’altra formulazione «expected tuple struct or tuple variant»: tonde dopo qualcosa che non ha dati tra tonde, come Status::Active(). In entrambi i casi si corregge in una riga. (Questa pagina fa parte di Errori del compilatore Rust spiegati.)
Il messaggio di errore
Sezione intitolata “Il messaggio di errore”error[E0532]: expected unit struct, unit variant or constant, found tuple variant `Shape::Circle` --> src/main.rs:8:9 |2 | Circle(f64), | ----------- `Shape::Circle` defined here...8 | Shape::Circle => "circle", // ❌ `Circle` holds a value | ^^^^^^^^^^^^^ help: use the tuple variant pattern syntax instead: `Shape::Circle(_)`Il compilatore dice: qui si aspettava una unit struct, una variante senza dati o una costante, e invece ha trovato una variante tupla. Questo è il programma che produce l’errore:
enum Shape { Circle(f64), Square(f64),}
fn name(shape: &Shape) -> &'static str { match shape { Shape::Circle => "circle", // ❌ `Circle` holds a value Shape::Square(_) => "square", }}
fn main() { println!("{}", name(&Shape::Circle(1.0)));}Cosa significa
Sezione intitolata “Cosa significa”Il ^^^ indica Shape::Circle alla riga 8, e il --- alla riga 2 mostra com’era definita: Circle(f64), una variante tupla che porta un f64. Un pattern fatto solo di un nome, senza niente dopo, deve essere una di queste tre cose:
- una unit struct, come
struct Empty; - una variante unit, cioè senza dati, come
Shape::EmptyoNone - una costante, come
const LIMIT: u32 = 100;
Shape::Circle non è nessuna delle tre. La riga di help ti dà subito la correzione: Shape::Circle(_), «un cerchio, qualunque sia il suo valore».
L’altra prima riga di E0532 è l’immagine allo specchio: expected tuple struct or tuple variant, found unit variant `Status::Active` (oppure found struct, o found constant). Lì sei tu ad aver scritto le tonde dopo un nome, e la cosa che hai nominato non accetta valori tra tonde.
È come un modulo che chiede «Animale: cane (nome: ____)». Scrivere solo «cane» lascia vuota la casella del nome, e scrivere «pesce (nome: Bolla)» dove il modulo dice «pesce» senza casella aggiunge una casella che non c’è.
Perché Rust si comporta così
Sezione intitolata “Perché Rust si comporta così”Ogni struct e ogni variante di enum ha una di tre forme, e la scrivi allo stesso modo quando la crei e quando la confronti (vedi Enum in Rust):
| Tipo | Crearla | Confrontarla |
|---|---|---|
Unit: Empty |
Shape::Empty |
Shape::Empty |
Tupla: Circle(f64) |
Shape::Circle(1.0) |
Shape::Circle(r) o Shape::Circle(..) |
Struct: Rect { w: f64, h: f64 } |
Shape::Rect { w: 2.0, h: 3.0 } |
Shape::Rect { w, h } o Shape::Rect { .. } |
Visto che le forme sono rigide, un pattern somiglia sempre al valore che confronta, e leggendo un match vedi quali dati ha ogni ramo. Aiuta anche quando cambi un tipo: se Empty più avanti riceve un valore e diventa Empty(u32), ogni vecchio ramo Shape::Empty viene segnalato, invece di confrontare in silenzio qualcosa di nuovo.
Come risolverlo
Sezione intitolata “Come risolverlo”Soluzione 1: aggiungi (_), (..) o dei nomi per i valori
Sezione intitolata “Soluzione 1: aggiungi (_), (..) o dei nomi per i valori”Scegli questa quando il messaggio dice found tuple variant o found tuple struct, il caso più comune di E0532. Usa _ per ogni valore che non ti serve, .. per saltarli tutti in una volta, oppure un nome quando vuoi usare il valore:
enum Shape { Circle(f64), Rect(f64, f64), Empty,}
fn name(shape: &Shape) -> &'static str { match shape { Shape::Circle(_) => "cerchio", // ✅ un campo, ignorato Shape::Rect(..) => "rettangolo", // ✅ qualsiasi numero di campi, tutti ignorati Shape::Empty => "niente", // una variante unit: niente tonde }}
fn area(shape: &Shape) -> f64 { match shape { Shape::Circle(r) => 3.14 * r * r, // ✅ leghiamo il campo perché ci serve Shape::Rect(w, h) => w * h, Shape::Empty => 0.0, }}
fn main() { let shapes = [Shape::Circle(1.0), Shape::Rect(2.0, 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.14rettangolo: 6.00niente: 0.00cerchi: 1(..) è comodo per le varianti con più valori, e continua a funzionare se in futuro ne aggiungi uno. Vedi Pattern matching in Rust.
Soluzione 2: togli le () da una variante unit
Sezione intitolata “Soluzione 2: togli le () da una variante unit”Scegli questa quando il messaggio dice found unit variant o found unit struct. La variante non contiene dati, quindi non c’è niente da mettere tra tonde:
error[E0532]: expected tuple struct or tuple variant, found unit variant `Status::Active` --> src/main.rs:8:9 |2 | Active, | ------ `Status::Active` defined here...8 | Status::Active() => "active", // ❌ `Active` holds no data | ^^^^^^^^^^^^^^^^ help: use this syntax instead: `Status::Active`Il programma che lo produce:
enum Status { Active, Banned(String),}
fn label(s: &Status) -> &'static str { match s { Status::Active() => "active", // ❌ `Active` holds no data Status::Banned(_) => "banned", }}
fn main() { println!("{}", label(&Status::Active));}Scrivi solo il nome, sia nel pattern sia dove crei il valore:
#[derive(Debug)]enum Status { Active, Banned(String),}
fn label(s: &Status) -> String { match s { Status::Active => String::from("attivo"), // ✅ variante unit: niente () Status::Banned(reason) => format!("bannato ({})", reason), }}
fn main() { println!("{}", label(&Status::Active)); println!("{}", label(&Status::Banned(String::from("spam")))); let s = Status::Active; // ✅ e niente () nemmeno quando lo crei println!("{:?}", s);}Output:
attivobannato (spam)ActiveSe volevi che la variante portasse dei dati, cambia invece la definizione, per esempio Active(u64) per un timestamp «attivo da», e allora Status::Active(_) è il pattern giusto.
Soluzione 3: usa le graffe per una struct con campi nominati
Sezione intitolata “Soluzione 3: usa le graffe per una struct con campi nominati”Scegli questa quando il messaggio dice found struct. Una struct con campi nominati, struct Point { x: i32, y: i32 }, si scompone con graffe e nomi dei campi, non con le tonde:
error[E0532]: expected tuple struct or tuple variant, found struct `Point` --> src/main.rs:8:9 |1 | / struct Point {2 | | x: i32,3 | | y: i32,4 | | } | |_- `Point` defined here...8 | let Point(x, y) = p; // ❌ `Point` has named fields | ^^^^^^^^^^^ help: use struct pattern syntax instead: `Point { x, y }`Il programma che lo produce:
struct Point { x: i32, y: i32,}
fn main() { let p = Point { x: 3, y: 4 }; let Point(x, y) = p; // ❌ `Point` has named fields println!("{} {}", x, y);}Il suggerimento di rustc Point { x, y } è esattamente quello giusto. Usa campo: nome quando vuoi un nome di variabile diverso:
struct Point { x: i32, y: i32,}
struct Meters(f64); // una tuple struct: qui le tonde sono giuste
fn main() { let p = Point { x: 3, y: 4 }; let Point { x, y } = p; // ✅ graffe e nomi dei campi println!("x = {}, y = {}", x, y);
let q = Point { x: -1, y: 7 }; let Point { x: left, y: up } = q; // ✅ rinomina mentre scomponi println!("sinistra = {}, su = {}", left, up);
let Meters(m) = Meters(2.5); // ✅ tuple struct, pattern tupla println!("{} m", m);}Output:
x = 3, y = 4sinistra = -1, su = 72.5 mPer una variante di enum con campi nominati, Shape::Rect(w, h) per Rect { w: f64, h: f64 }, lo stesso sbaglio dà un codice diverso, E0164. La correzione è la stessa: le graffe.
Soluzione 4: usa una costante o una match guard al posto di una chiamata di funzione
Sezione intitolata “Soluzione 4: usa una costante o una match guard al posto di una chiamata di funzione”Scegli questa quando il messaggio dice expected a pattern, found a function call. Un pattern deve essere noto in fase di compilazione, e una chiamata di funzione non lo è:
error[E0532]: expected a pattern, found a function call --> src/main.rs:7:14 |7 | Some(limit()) => "full", // ❌ a function call can't be a pattern | ^^^^^ not a tuple struct or tuple variant | = note: function calls are not allowed in patterns: <https://doc.rust-lang.org/book/ch19-00-patterns.html>Il programma che lo produce:
fn limit() -> u32 { 100}
fn status(users: Option<u32>) -> &'static str { match users { Some(limit()) => "full", // ❌ a function call can't be a pattern Some(_) => "open", None => "closed", }}
fn main() { println!("{}", status(Some(100)));}Se il valore non cambia mai, rendilo una const; le costanti si possono usare dentro i pattern. Se va calcolato, lega il valore a un nome e confronta in una match guard:
const LIMIT: u32 = 100; // una costante si può usare dentro un pattern
fn limit_for(premium: bool) -> u32 { if premium { 500 } else { 100 }}
fn status(users: Option<u32>) -> &'static str { match users { Some(LIMIT) => "pieno", // ✅ una costante Some(_) => "aperto", None => "chiuso", }}
fn status_for(users: Option<u32>, premium: bool) -> &'static str { match users { Some(n) if n >= limit_for(premium) => "pieno", // ✅ chiama la funzione in una guard Some(_) => "aperto", None => "chiuso", }}
fn main() { println!("{}", status(Some(100))); println!("{}", status(Some(42))); println!("{}", status(None)); println!("{}", status_for(Some(100), false)); println!("{}", status_for(Some(100), true));}Output:
pienoapertochiusopienoapertoLe match guard sono spiegate in Pattern matching in Rust.
Dove lo incontri di solito
Sezione intitolata “Dove lo incontri di solito”Dopo che una variante unit riceve un valore. Event::Logout era una variante unit, e l’hai cambiata in Logout(u64). Ogni ramo Event::Logout => ora dà E0532. Correzione: Event::Logout(_) =>, oppure Event::Logout(at) => se ti serve il valore.
Controllare solo il tipo di un valore. Se arrivi da Java o TypeScript, potresti scrivere if let Shape::Circle = shape per chiedere «è un cerchio?». Scrivi if let Shape::Circle(_) = shape, oppure matches!(shape, Shape::Circle(_)) per ottenere al volo un bool.
Senza il prefisso Shape:: è E0530. Se scrivi un nome nudo, come Ok => o Circle => dopo use Shape::*;, rustc lo legge come una nuova variabile. Segnala E0530, match bindings cannot shadow tuple variants, con l’help try specify the pattern arguments: `Ok(..)` . Stessa correzione: aggiungi le tonde.
Errori correlati
Sezione intitolata “Errori correlati”- E0533: expected unit struct, unit variant or constant, found struct variant: lo stesso sbaglio per le varianti con campi nominati; aggiungi
{ .. }. - E0164: expected tuple struct or tuple variant, found struct variant: tonde su una variante con campi nominati, o su una costante o funzione associata.
- E0023: numero sbagliato di campi in un pattern tupla (in inglese): le tonde sono giuste, ma hai dato troppi o troppo pochi nomi.
- E0026: struct or variant does not have a field named x: un nome di campo sbagliato dentro le graffe di un pattern.
- E0004: non-exhaustive patterns: dopo aver sistemato i rami, il
matchdeve comunque coprire ogni variante. - Tutti gli errori del compilatore spiegati
Verifica veloce
Sezione intitolata “Verifica veloce”Verifica veloce
1. Con enum Shape { Circle(f64), Empty }, quale ramo di match compila?
2. rustc dice "expected tuple struct or tuple variant, found unit variant Status::Active". Qual è la correzione?
3. struct Point { x: i32, y: i32 }: come la scomponi con let?
Punteggio: 0 / 3
Per approfondire
Sezione intitolata “Per approfondire”- E0532 — Rust error codes index (in inglese): la spiegazione ufficiale di questo errore.
- Pattern Syntax — The Rust Book (in inglese): scomporre struct ed enum, ignorare valori con
_e.., e le match guard. - Destructuring enums — Rust by Example (in inglese): varianti unit e tupla confrontate fianco a fianco.
- Destructuring structs — Rust by Example (in inglese): graffe per i campi nominati, tonde per le tuple struct.
- Patterns — The Rust Reference (in inglese): le regole esatte dei pattern di percorso, di tuple struct e di struct.