Salta ai contenuti

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.)

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

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::Empty o None
  • 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’è.

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.

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.14
rettangolo: 6.00
niente: 0.00
cerchi: 1
▶ Provalo tu

(..) è comodo per le varianti con più valori, e continua a funzionare se in futuro ne aggiungi uno. Vedi Pattern matching in Rust.

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:

attivo
bannato (spam)
Active
▶ Provalo tu

Se 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 = 4
sinistra = -1, su = 7
2.5 m
▶ Provalo tu

Per 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:

pieno
aperto
chiuso
pieno
aperto
▶ Provalo tu

Le match guard sono spiegate in Pattern matching in Rust.

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.

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