Pular para o conteúdo

Erro E0027 do Rust: pattern does not mention field X (campo fora do padrão)

O E0027 quer dizer: você está desmontando uma struct ou uma variante de enum com um padrão, como let Order { item, quantity } = order;, e não citou todos os campos. Em Rust, um padrão de struct precisa dar conta de todos os campos, seja citando cada um pelo nome, seja dizendo “e o resto” com ... Este é um dos erros mais amigáveis que existem: o rustc mostra a correção exata, e ela quase sempre é só dois pontos. (Esta página faz parte de Erros do compilador Rust explicados.)

error[E0027]: pattern does not mention fields `id`, `paid`
--> src/main.rs:10:9
|
10 | let Order { item, quantity } = order; // ❌ `id` e `paid` não foram citados
| ^^^^^^^^^^^^^^^^^^^^^^^^ missing fields `id`, `paid`
|
help: include the missing fields in the pattern
|
10 | let Order { item, quantity, id, paid } = order; // ❌ `id` e `paid` não foram citados
| ++++++++++
help: if you don't care about these missing fields, you can explicitly ignore them
|
10 | let Order { item, quantity, id: _, paid: _ } = order; // ❌ `id` e `paid` não foram citados
| ++++++++++++++++
help: or always ignore missing fields here
|
10 | let Order { item, quantity, .. } = order; // ❌ `id` e `paid` não foram citados
| ++++

Em português: “o padrão não menciona os campos id e paid”. O rótulo diz que esses campos estão faltando, e as três ajudas sugerem: incluir os campos que faltam no padrão, ignorá-los de forma explícita, ou sempre ignorar os campos que faltam aqui.

Este é o programa que gera o erro:

struct Order {
id: u32,
item: String,
quantity: u32,
paid: bool,
}
fn main() {
let order = Order { id: 1, item: String::from("teclado"), quantity: 2, paid: true };
let Order { item, quantity } = order; // ❌ `id` e `paid` não foram citados
println!("{} x {}", quantity, item);
}

A primeira linha lista os campos que o seu padrão deixou de fora (id e paid). O ^^^ sublinha o padrão inteiro, porque o problema não é uma palavra errada, é algo que está faltando.

Depois o rustc dá três sugestões help:. Todas são válidas, e cada uma quer dizer uma coisa diferente:

  • include the missing fields (inclua os campos que faltam): cite os campos, e você ganha também as variáveis id e paid.
  • explicitly ignore them (ignore-os de forma explícita): escreva id: _, paid: _. Você não ganha variáveis, mas listou todos os campos pelo nome.
  • always ignore missing fields here (sempre ignore os campos que faltam aqui): escreva ... Quer dizer “e qualquer outro campo, não me importo com eles”.

É como uma lista de presença na porta que diz “marque todas as caixas, ou marque Outros: pular”. Você não pode simplesmente deixar caixas em branco.

Um padrão de struct em Rust deve ser completo, a não ser que você diga o contrário. Isso deixa a sua intenção clara para quem ler o código depois. Order { item, quantity, .. } diz “só preciso destes dois”. Order { id, item, quantity, paid } diz “pensei em cada campo”. Veja Ignorando partes com _ e ...

A grande vantagem aparece quando a struct muda. Se alguém acrescentar um campo discount a Order, um padrão que lista todos os campos pelo nome quebra com E0027, e isso aponta para um código que talvez precise lidar com o campo novo. Um padrão com .. continua compilando. O Rust deixa você escolher qual comportamento quer, mas não vai adivinhar por você.

Escolha esta na maioria das vezes. Se você só precisa de alguns campos, termine o padrão com ... Funciona em let, match, if let e em parâmetros de funções, e precisa vir por último.

struct Order {
id: u32,
item: String,
quantity: u32,
paid: bool,
}
fn main() {
let order = Order { id: 1, item: String::from("teclado"), quantity: 2, paid: true };
let Order { item, quantity, .. } = order; // ✅ o `..` pula `id` e `paid`
println!("{} x {}", quantity, item);
let orders = [
Order { id: 2, item: String::from("mouse"), quantity: 1, paid: false },
Order { id: 3, item: String::from("monitor"), quantity: 1, paid: true },
];
for order in &orders {
match order {
Order { paid: true, item, .. } => println!("enviar o {}", item),
Order { id, .. } => println!("o pedido #{} está aguardando pagamento", id),
}
}
}

Saída:

2 x teclado
o pedido #2 está aguardando pagamento
enviar o monitor
▶ Experimente você mesmo

Repare no paid: true do primeiro braço: um campo num padrão também pode ser comparado com um valor, e o .. continua cuidando dos outros.

Correção 2: Cite o campo que falta, ou ignore-o pelo nome com _

Seção intitulada “Correção 2: Cite o campo que falta, ou ignore-o pelo nome com _”

Escolha esta quando você precisa mesmo do campo, ou quando você quer que o padrão quebre se um campo for acrescentado depois. O mesmo erro aparece num match sobre uma variante de enum com campos nomeados:

error[E0027]: pattern does not mention field `y`
--> src/main.rs:9:9
|
9 | Message::Move { x } => println!("mover para x = {}", x), // ❌ `y` não foi citado
| ^^^^^^^^^^^^^^^^^^^ missing field `y`

O rustc diz que o padrão não menciona o campo y.

O programa por trás dele:

enum Message {
Move { x: i32, y: i32 },
Quit,
}
fn main() {
let m = Message::Move { x: 1, y: 2 };
match m {
Message::Move { x } => println!("mover para x = {}", x), // ❌ `y` não foi citado
Message::Quit => println!("sair"),
}
}

Um movimento tem duas coordenadas, e o código deveria mesmo usar as duas. Então cite o y. Quando um campo realmente não importa, y: _ diz isso em voz alta, e ainda assim o lista pelo nome:

enum Message {
Move { x: i32, y: i32 },
Quit,
}
fn main() {
let messages = [Message::Move { x: 1, y: 2 }, Message::Move { x: 5, y: 0 }, Message::Quit];
for m in &messages {
match m {
Message::Move { x, y: 0 } => println!("deslizar pelo chão até x = {}", x),
Message::Move { x, y } => println!("mover para ({}, {})", x, y), // ✅ os dois campos
Message::Quit => println!("sair"),
}
}
// todos os campos listados pelo nome: acrescentar um campo a `Move` quebra isto de propósito
if let Message::Move { x, y: _ } = &messages[0] {
println!("primeiro x = {}", x);
}
}

Saída:

mover para (1, 2)
deslizar pelo chão até x = 5
sair
primeiro x = 1
▶ Experimente você mesmo

Se você cita um campo só para ignorá-lo, escreva y: _, e não um y simples. Um y simples que você nunca usa dá um aviso de “unused variable” (variável não usada).

Correção 3: Corrija um nome de campo escrito errado

Seção intitulada “Correção 3: Corrija um nome de campo escrito errado”

Escolha esta quando o E0027 vem junto com o E0026 na mesma linha. Por exemplo, Shape::Circle { r } numa variante cujo campo é radius dá os dois: E0026 para r (esse campo não existe) e E0027 para radius (não foi citado). A ajuda do E0027 vai sugerir acrescentar radius ao lado de r, mas não é isso que você quer. A correção de verdade é trocar o nome errado: Shape::Circle { radius }, ou Shape::Circle { radius: r } para manter o nome curto da variável. Aí os dois erros somem de uma vez. Veja exemplos na página do E0026.

Depois de acrescentar um campo a uma struct. Você acrescenta created_at a Order, e todo padrão que listava todos os campos agora dá E0027. É a verificação fazendo o trabalho dela. Decida caso a caso: este código precisa de created_at? Se sim, cite o campo; se não, acrescente ...

Parâmetros de funções. fn print_order(&Order { item, quantity }: &Order) também dá E0027. Correção: &Order { item, quantity, .. }. Veja Padrões no let e nos parâmetros de funções.

Tuple structs e variantes de tupla. Para struct Color(u8, u8, u8);, o padrão Color(r) também está incompleto, mas o rustc mostra isso como E0023, “this pattern has 1 field, but the corresponding tuple struct has 3 fields” (este padrão tem 1 campo, mas a tuple struct correspondente tem 3). A ideia da correção é a mesma: Color(r, ..) ou Color(r, _, _).

Teste o que aprendeu

1. struct Point { x: i32, y: i32, z: i32 }. Qual padrão compila e dá a você só o x?

2. Qual é a diferença entre Order { item, .. } e Order { item, id: _, quantity: _, paid: _ }?

3. Você recebe E0026 para r e E0027 para radius na mesma linha. Qual é a melhor correção?

Pontuação: 0 / 3