Salta ai contenuti

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

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 fields
8 + 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 }));
}

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.

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.

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

Se 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.00
▶ Provalo tu

Questo 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 patterns

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

caldo
fresco
-3 gradi
gelo
▶ Provalo tu

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

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 variant

Il 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: muto
2: basso
7: normale
10: al massimo
255: normale
▶ Provalo tu

Lo stesso vale per le costanti della libreria standard: u32::MAX(_) è E0164, u32::MAX è un pattern valido.

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.

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