Erro E0164 do Rust: expected tuple struct or tuple variant, found struct variant
O E0164 quer dizer: você escreveu parênteses num padrão, como Shape::Circle(r), depois de um nome que não recebe valores entre parênteses. No Rust de hoje você encontra esse erro em três situações: uma variante de enum com campos nomeados (Circle { radius: f64 }) casada como se fosse uma variante de tupla, uma função associada como Celsius::new(d) usada como padrão, e uma constante associada como Volume::MAX(_) com parênteses depois. Cada uma tem uma correção curta e clara. (Esta página faz parte de Erros do compilador Rust explicados.)
A mensagem de erro
Seção intitulada “A mensagem de erro”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 |Em português: “era esperada uma tuple struct ou uma variante de tupla, mas foi encontrada a variante de struct Shape::Circle”. A ajuda diz que o campo da variante de struct está sendo ignorado e mostra como escrever o padrão com chaves.
Este é o programa que gera o erro:
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 }));}(O comentário // ❌ `Circle` has named fields quer dizer “Circle tem campos nomeados”. Ele fica em inglês porque aparece na saída do compilador.)
O que significa
Seção intitulada “O que significa”O ^^^ cobre o padrão inteiro Shape::Circle(r), e o rótulo diz o que o Rust esperava ali: “a tuple struct or tuple variant” (uma tuple struct ou uma variante de tupla). Só esses dois tipos de coisa são escritos com parênteses num padrão, porque só eles guardam valores por posição, como Some(x) ou Meters(m).
Shape::Circle é uma variante de struct. O valor dela tem um nome, radius, e campos nomeados são casados com chaves: Shape::Circle { radius }.
Cuidado com o help: aqui. Ele sugere Shape::Circle { radius: _ }, que corrige o padrão mas ignora o raio. O nosso braço usa r, então copiar a sugestão do jeito que está dá um erro novo, o E0425 cannot find value `r` in this scope (valor r não encontrado neste escopo). Quando você precisa do valor, dê um nome a ele dentro das chaves, como na Correção 1.
É como um formulário com campos identificados, “Largura: … Altura: …”, e você escreveu “3, 4” do lado do título. Os números podem até estar certos, mas o formulário quer cada um no seu campo.
Por que o Rust faz isso
Seção intitulada “Por que o Rust faz isso”Um padrão precisa se parecer com o valor que ele casa. O Rust tem dois jeitos de guardar dados numa variante, e cada um tem o seu padrão (veja Enums podem guardar dados):
| Definida como | Criada com | Casada com |
|---|---|---|
Circle(f64) (variante de tupla) |
Shape::Circle(1.0) |
Shape::Circle(r) |
Circle { radius: f64 } (variante de struct) |
Shape::Circle { radius: 1.0 } |
Shape::Circle { radius } |
Campos nomeados são casados pelo nome, não pela posição, então a ordem no padrão não importa, e acrescentar um campo depois não desloca os outros em silêncio. Misturar os dois estilos é proibido, então nunca fica a dúvida de qual valor vai em qual lugar.
Os padrões também são verificados em tempo de compilação, então eles não podem rodar código. É por isso que o nome de uma função seguido de (d) também não pode ser um padrão, mesmo quando a função monta exatamente o valor que você está casando. Mais em Pattern matching.
Como corrigir
Seção intitulada “Como corrigir”Correção 1: Use chaves com os nomes dos campos
Seção intitulada “Correção 1: Use chaves com os nomes dos campos”Escolha esta quando a mensagem diz found struct variant, que é o E0164 mais comum. Escreva o nome do campo (o Rust cria uma variável com esse nome), campo: novo_nome para escolher outro nome, ou { .. } para ignorar todos os campos:
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 do campo entre chaves Shape::Rect { w: width, h: height } => width * height, // ✅ campo: novo nome }}
fn name(shape: &Shape) -> &'static str { match shape { Shape::Circle { .. } => "círculo", // ✅ "qualquer círculo" Shape::Rect { .. } => "retângulo", }}
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)); }}Saída:
círculo: 3.14retângulo: 6.00Se você citar alguns campos mas não todos, acrescente .. no fim, como em Shape::Rect { w, .. }. Sem ele, você recebe o E0027, e um nome de campo escrito errado dá o E0026.
Correção 2: Transforme a variante numa variante de tupla
Seção intitulada “Correção 2: Transforme a variante numa variante de tupla”Escolha esta quando parênteses são mesmo o que você quer: a variante tem um único valor óbvio, e você prefere escrever Shape::Circle(1.0) em todo lugar. Mude a definição, e o padrão Circle(r) passa a estar certo:
enum Shape { Circle(f64), // ✅ agora é uma variante de tupla: um valor sem nome Rect { w: f64, h: f64 },}
fn area(shape: &Shape) -> f64 { match shape { Shape::Circle(r) => 3.14 * r * r, // ✅ parênteses combinam com variante de tupla Shape::Rect { w, h } => w * h, }}
fn main() { let small = Shape::Circle(1.0); // criada com parênteses também 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));}Saída:
3.14 12.56 2.00Isso muda o tipo, então todo lugar que cria ou casa Circle também precisa passar a usar parênteses. O compilador aponta cada um. Para dois ou mais valores, campos nomeados costumam ser mais claros.
Correção 3: Case a própria tuple struct e chame funções num guard
Seção intitulada “Correção 3: Case a própria tuple struct e chame funções num guard”Escolha esta quando a mensagem diz found associated function (foi encontrada uma função associada) e o rótulo diz `fn` calls are not allowed in patterns (chamadas de fn não são permitidas em padrões). Você escreveu um construtor como Celsius::new(d) onde o Rust precisa de um padrão:
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 patternsO programa por trás dele:
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 é uma tuple struct, então o padrão é o próprio nome da struct: Celsius(d). Tudo o que precisa de uma chamada de função ou de método vai para um match guard (o if ... depois do padrão):
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 => "quente", // ✅ a própria tuple struct, mais um guard Celsius(_) => "fresco", }}
fn describe(t: &Celsius) -> &'static str { match t { t if t.is_freezing() => "congelando", // ✅ métodos vão num guard _ => "acima de zero", }}
fn main() { println!("{}", feels(Celsius::new(30.0))); println!("{}", feels(Celsius::new(12.5))); let Celsius(d) = Celsius::new(-3.0); // ✅ também funciona com `let` println!("{} graus", d); println!("{}", describe(&Celsius::new(-3.0)));}Saída:
quentefresco-3 grauscongelandoSe o campo da struct for privado (ela mora em outro módulo), você não pode escrever Celsius(d) fora daquele módulo. Nesse caso, use um getter num guard, como t if t.degrees() > 25.0. Veja Match guards: adicionando um if.
Correção 4: Tire os parênteses depois de uma constante
Seção intitulada “Correção 4: Tire os parênteses depois de uma constante”Escolha esta quando a mensagem diz found associated constant (foi encontrada uma constante associada). Uma constante já é um padrão completo. Ela casa com um único valor exato, então não há nada para colocar entre parênteses:
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 variantO rustc aponta para Volume::MAX(_) e diz que isso não é uma tuple struct nem uma variante de tupla.
O programa por trás dele:
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));}Escreva a constante sozinha:
struct Volume;
impl Volume { const MAX: u8 = 10;}
fn label(level: u8) -> &'static str { match level { 0 => "mudo", Volume::MAX => "no máximo", // ✅ uma constante, sozinha 1..=3 => "baixo", _ => "normal", }}
fn main() { for level in [0, 2, 7, 10, u8::MAX] { println!("{}: {}", level, label(level)); }}Saída:
0: mudo2: baixo7: normal10: no máximo255: normalO mesmo vale para as constantes da biblioteca padrão: u32::MAX(_) dá E0164, e u32::MAX é um padrão válido.
Onde você costuma ver esse erro
Seção intitulada “Onde você costuma ver esse erro”Depois de mudar uma variante para campos nomeados. Você transformou Move(i32, i32) em Move { x: i32, y: i32 } para deixar mais claro. Agora todo braço antigo Command::Move(x, y) => dá E0164. Correção: Command::Move { x, y } =>.
Casar com uma função de “parse”. Algo como match input { Version::parse(v) => ... }, na esperança de que a função rode durante o match. Correção: chame a função antes e depois faça match no resultado: match Version::parse(input) { Some(v) => ..., None => ... }.
Funções soltas, structs comuns e variantes unitárias dão E0532. O mesmo erro de parênteses aparece como E0532 quando o nome não é acessado por meio de um tipo: uma função comum (Some(limit()), expected a pattern, found a function call), uma struct com campos nomeados (let Point(x, y) = p;, found struct `Point` ) ou uma variante unitária (Status::Active()). As correções são as mesmas desta página.
Erros relacionados
Seção intitulada “Erros relacionados”- E0532: expected tuple struct or tuple variant, found unit variant or struct: a mesma confusão com structs comuns, variantes unitárias e funções soltas, e o contrário (uma variante de tupla escrita sem parênteses).
- E0533: expected unit struct, unit variant or constant, found struct variant: uma variante de struct escrita sem chave nenhuma, como
Shape::Circle =>. - E0026: struct or variant does not have a field named x: as chaves estão certas, mas um nome de campo dentro delas está errado.
- E0027: pattern does not mention field x: chaves que deixam campos de fora; acrescente
... - E0425: cannot find value in this scope: o que você recebe se copiar a sugestão
{ radius: _ }mas continuar usandor. - Todos os erros do compilador explicados
Teste o que aprendeu
Seção intitulada “Teste o que aprendeu”Teste o que aprendeu
1. Para enum Shape { Circle { radius: f64 } }, qual braço usa o raio do jeito certo?
2. Celsius::new(d) => ... dá "fn calls are not allowed in patterns". Celsius é struct Celsius(f64);. Qual padrão funciona?
3. Como você casa a constante associada Volume::MAX?
Pontuação: 0 / 3
Para saber mais
Seção intitulada “Para saber mais”- E0164 — Rust error codes index (em inglês): a explicação oficial, com o exemplo da constante associada.
- Pattern Syntax — The Rust Book (em inglês): como desestruturar enums com chaves ou parênteses, ignorar campos com
..e usar match guards. - Destructuring enums — Rust by Example (em inglês): variantes de tupla e de struct casadas lado a lado.
- Patterns — The Rust Reference (em inglês): quais caminhos podem aparecer em padrões de tuple struct e de struct.