Errore Rust E0164: expected tuple struct or tuple variant, found struct variant
E0164 significa: hai scritto delle tonde in un pattern, come Shape::Circle(r), dopo un nome che non accetta valori tra tonde. Nel Rust di oggi lo incontri in tre situazioni: una variante di enum con campi nominati (Circle { radius: f64 }) confrontata come se fosse una variante tupla, una funzione associata come Celsius::new(d) usata come pattern, e una costante associata come Volume::MAX(_) seguita da tonde. Ognuna ha una correzione breve e chiara. (Questa pagina fa parte di Errori del compilatore Rust spiegati.)
Il messaggio di errore
Sezione intitolata “Il messaggio di errore”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 |Il compilatore dice: si aspettava una tuple struct o una variante tupla, e invece ha trovato una variante struct. Questo è il programma che produce l’errore:
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 }));}Cosa significa
Sezione intitolata “Cosa significa”Il ^^^ copre tutto il pattern Shape::Circle(r), e l’etichetta dice che cosa si aspettava Rust lì: «a tuple struct or tuple variant». Solo questi due tipi di cose si scrivono con le tonde in un pattern, perché solo loro contengono valori per posizione, come Some(x) o Meters(m).
Shape::Circle è una variante struct. Il suo valore ha un nome, radius, e i campi nominati si confrontano con le graffe: Shape::Circle { radius }.
Attenzione all’help: in questo caso. Suggerisce Shape::Circle { radius: _ }, che sistema il pattern ma ignora il raggio. Il nostro ramo usa r, quindi copiare il suggerimento così com’è dà un nuovo errore, E0425 cannot find value `r` in this scope. Quando ti serve il valore, dagli un nome dentro le graffe, come nella soluzione 1.
È come un modulo con caselle etichettate, «Larghezza: … Altezza: …», dove tu hai scritto «3, 4» accanto al titolo. I numeri potrebbero essere giusti, ma il modulo vuole ciascuno nella sua casella.
Perché Rust si comporta così
Sezione intitolata “Perché Rust si comporta così”Un pattern deve somigliare al valore che confronta. Rust ha due modi per contenere dati, e ognuno ha il suo pattern (vedi Enum in Rust):
| Definita come | Creata con | Confrontata con |
|---|---|---|
Circle(f64) (variante tupla) |
Shape::Circle(1.0) |
Shape::Circle(r) |
Circle { radius: f64 } (variante struct) |
Shape::Circle { radius: 1.0 } |
Shape::Circle { radius } |
I campi nominati si confrontano per nome, non per posizione, quindi l’ordine nel pattern non conta e aggiungere un campo in futuro non sposta in silenzio gli altri. Mescolare i due stili non è permesso, così non c’è mai il dubbio su quale valore vada dove.
I pattern vengono anche controllati in fase di compilazione, quindi non possono eseguire codice. Ecco perché neanche il nome di una funzione seguito da (d) può fare da pattern, anche quando la funzione costruisce esattamente il valore che stai confrontando. Di più in Pattern matching in Rust.
Come risolverlo
Sezione intitolata “Come risolverlo”Soluzione 1: usa le graffe con i nomi dei campi
Sezione intitolata “Soluzione 1: usa le graffe con i nomi dei campi”Scegli questa quando il messaggio dice found struct variant, il caso più comune di E0164. Scrivi il nome del campo (Rust crea una variabile con quel nome), campo: nuovo_nome per sceglierne un altro, oppure { .. } per ignorare tutti i campi:
enum Shape { Circle { radius: f64 }, Rect { w: f64, h: f64 },}
fn area(shape: &Shape) -> f64 { match shape { Shape::Circle { radius } => 3.14 * radius * radius, // ✅ nome del campo tra graffe Shape::Rect { w: width, h: height } => width * height, // ✅ campo: nuovo nome }}
fn name(shape: &Shape) -> &'static str { match shape { Shape::Circle { .. } => "cerchio", // ✅ «un cerchio qualsiasi» Shape::Rect { .. } => "rettangolo", }}
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)); }}Output:
cerchio: 3.14rettangolo: 6.00Se elenchi alcuni campi ma non tutti, aggiungi .. alla fine, come Shape::Rect { w, .. }. Senza, ottieni E0027, e un nome di campo scritto male dà E0026.
Soluzione 2: trasforma la variante in una variante tupla
Sezione intitolata “Soluzione 2: trasforma la variante in una variante tupla”Scegli questa quando vuoi proprio le tonde: la variante ha un solo valore ovvio, e preferisci scrivere Shape::Circle(1.0) dappertutto. Cambia la definizione, e il pattern Circle(r) diventa corretto:
enum Shape { Circle(f64), // ✅ ora è una variante tupla: un valore senza nome Rect { w: f64, h: f64 },}
fn area(shape: &Shape) -> f64 { match shape { Shape::Circle(r) => 3.14 * r * r, // ✅ le tonde vanno bene per una variante tupla Shape::Rect { w, h } => w * h, }}
fn main() { let small = Shape::Circle(1.0); // si crea anche con le tonde 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));}Output:
3.14 12.56 2.00Questo cambia il tipo, quindi anche ogni punto che crea o confronta Circle deve passare alle tonde. Il compilatore te li elenca uno per uno. Con due o più valori, di solito i campi nominati sono più chiari.
Soluzione 3: confronta la tuple struct stessa, e chiama le funzioni in una guard
Sezione intitolata “Soluzione 3: confronta la tuple struct stessa, e chiama le funzioni in una guard”Scegli questa quando il messaggio dice found associated function e l’etichetta dice `fn` calls are not allowed in patterns (le chiamate di funzione non sono ammesse nei pattern). Hai scritto un costruttore come Celsius::new(d) dove Rust ha bisogno di un pattern:
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 patternsIl programma che 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 è una tuple struct, quindi il pattern è il nome stesso della struct: Celsius(d). Tutto ciò che richiede una chiamata di funzione o di metodo va in una match guard (if ... dopo il pattern):
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 => "caldo", // ✅ la tuple struct stessa, più una guard Celsius(_) => "fresco", }}
fn describe(t: &Celsius) -> &'static str { match t { t if t.is_freezing() => "gelo", // ✅ i metodi vanno in una guard _ => "niente gelo", }}
fn main() { println!("{}", feels(Celsius::new(30.0))); println!("{}", feels(Celsius::new(12.5))); let Celsius(d) = Celsius::new(-3.0); // ✅ funziona anche con `let` println!("{} gradi", d); println!("{}", describe(&Celsius::new(-3.0)));}Output:
caldofresco-3 gradigeloSe il campo della struct è privato (perché vive in un altro modulo), fuori da quel modulo non puoi scrivere Celsius(d). Allora usa un getter in una guard, come t if t.degrees() > 25.0. Vedi Pattern matching in Rust.
Soluzione 4: togli le tonde dopo una costante
Sezione intitolata “Soluzione 4: togli le tonde dopo una costante”Scegli questa quando il messaggio dice found associated constant. Una costante è già un pattern completo. Corrisponde a un valore esatto, quindi non c’è niente da mettere tra tonde:
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 variantIl programma che 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));}Scrivi la costante da sola:
struct Volume;
impl Volume { const MAX: u8 = 10;}
fn label(level: u8) -> &'static str { match level { 0 => "muto", Volume::MAX => "al massimo", // ✅ una costante, da sola 1..=3 => "basso", _ => "normale", }}
fn main() { for level in [0, 2, 7, 10, u8::MAX] { println!("{}: {}", level, label(level)); }}Output:
0: muto2: basso7: normale10: al massimo255: normaleLo stesso vale per le costanti della libreria standard: u32::MAX(_) è E0164, u32::MAX è un pattern valido.
Dove lo incontri di solito
Sezione intitolata “Dove lo incontri di solito”Dopo aver passato una variante ai campi nominati. Hai trasformato Move(i32, i32) in Move { x: i32, y: i32 } per chiarezza. Ogni vecchio ramo Command::Move(x, y) => ora dà E0164. Correzione: Command::Move { x, y } =>.
Confrontare con una funzione «parser». Qualcosa come match input { Version::parse(v) => ... }, sperando che la funzione venga eseguita durante il confronto. Correzione: chiamala prima, poi fai il match sul risultato: match Version::parse(input) { Some(v) => ..., None => ... }.
Funzioni libere, struct semplici e varianti unit danno invece E0532. Lo stesso sbaglio con le tonde viene segnalato come E0532 quando il nome non si raggiunge attraverso un tipo: una funzione semplice (Some(limit()), expected a pattern, found a function call), una struct con campi nominati (let Point(x, y) = p;, found struct `Point` ), oppure una variante unit (Status::Active()). Le correzioni sono le stesse di questa pagina.
Errori correlati
Sezione intitolata “Errori correlati”- E0532: expected tuple struct or tuple variant, found unit variant or struct: la stessa confusione per struct semplici, varianti unit e funzioni libere, e il contrario (una variante tupla scritta senza tonde).
- E0533: expected unit struct, unit variant or constant, found struct variant: una variante struct scritta del tutto senza graffe, come
Shape::Circle =>. - E0026: struct or variant does not have a field named x: le graffe sono giuste, ma un nome di campo al loro interno è sbagliato.
- E0027: pattern does not mention field x: graffe che lasciano fuori dei campi; aggiungi
... - E0425: cannot find value in this scope: quello che ottieni se copi il suggerimento
{ radius: _ }ma continui a usarer. - Tutti gli errori del compilatore spiegati
Verifica veloce
Sezione intitolata “Verifica veloce”Verifica veloce
1. Con enum Shape { Circle { radius: f64 } }, quale ramo usa correttamente il raggio?
2. Celsius::new(d) => ... dà "fn calls are not allowed in patterns". Celsius è struct Celsius(f64);. Quale pattern funziona?
3. Come confronti la costante associata Volume::MAX?
Punteggio: 0 / 3
Per approfondire
Sezione intitolata “Per approfondire”- E0164 — Rust error codes index (in inglese): la spiegazione ufficiale, con l’esempio della costante associata.
- Pattern Syntax — The Rust Book (in inglese): scomporre gli enum con graffe o tonde, ignorare campi con
..e le match guard. - Destructuring enums — Rust by Example (in inglese): varianti tupla e struct confrontate fianco a fianco.
- Patterns — The Rust Reference (in inglese): quali percorsi possono comparire nei pattern di tuple struct e di struct.