Pular para o conteúdo

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

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
|

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

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.

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.14
retângulo: 6.00
▶ Experimente você mesmo

Se 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.00
▶ Experimente você mesmo

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

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

quente
fresco
-3 graus
congelando
▶ Experimente você mesmo

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

O 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: mudo
2: baixo
7: normal
10: no máximo
255: normal
▶ Experimente você mesmo

O mesmo vale para as constantes da biblioteca padrão: u32::MAX(_) dá E0164, e u32::MAX é um padrão válido.

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.

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