Erro E0063 do Rust: missing field in initializer (campo faltando)
O E0063 quer dizer: você está criando uma struct com Nome { ... }, mas não deu um valor para todos os campos. O Rust nunca preenche campos por você, então cada um precisa de um valor, nem que seja 0, false ou None. A mensagem diz o nome dos campos que faltam, então você sabe exatamente o que acrescentar. Este é um dos erros mais amigáveis do Rust. (Esta página faz parte de Erros do compilador Rust explicados.)
A mensagem de erro
Seção intitulada “A mensagem de erro”error[E0063]: missing field `email` in initializer of `User` --> src/main.rs:8:16 |8 | let user = User { | ^^^^ missing `email`Em português: “falta o campo email na inicialização de User”. O rótulo repete: “falta email”.
Este é o programa que gera o erro:
struct User { name: String, email: String, active: bool,}
fn main() { let user = User { name: String::from("Ferris"), active: true, // ❌ sem `email` }; println!("{}", user.name);}O que significa
Seção intitulada “O que significa”A primeira linha diz o nome do campo que falta (email) e da struct (User). O ^^^^ aponta para o nome da struct, onde você começou a montá-la, e não para uma linha específica, porque o problema é algo que não está ali.
Quando faltam mais campos, o rustc lista todos em ordem alfabética. Com dois ou três, você vê todos:
error[E0063]: missing fields `debug`, `retries` and `timeout_secs` in initializer of `Config`Com quatro ou mais, ele mostra três e conta o resto:
error[E0063]: missing fields `debug`, `port`, `retries` and 1 other field in initializer of `Config` --> src/main.rs:10:18 |10 | let config = Config { | ^^^^^^ missing `debug`, `port`, `retries` and 1 other field“1 other field” quer dizer que falta mais um campo. Olhe a definição de struct Config para ver a lista completa.
É como um formulário em que todos os campos são obrigatórios. Você não pode entregá-lo com o campo “e-mail” em branco, mesmo que pretendesse preencher depois.
Por que o Rust faz isso
Seção intitulada “Por que o Rust faz isso”Em muitas linguagens, um campo que falta vira null, 0 ou uma string vazia sem ninguém avisar. Aí o seu programa roda com um usuário sem e-mail, e quebra bem longe dali, muitas vezes em produção. O Rust não tem null e não inventa valores pelas suas costas. Um User sempre tem um email de verdade. Veja Definindo e criando uma struct.
Isso não quer dizer que você precisa digitar todos os campos toda vez. O Rust tem jeitos curtos de dizer “use os valores padrão” ou “copie o resto deste outro valor”, como mostram as correções abaixo. A questão é que você escolhe, e a escolha fica escrita no código.
Como corrigir
Seção intitulada “Como corrigir”Correção 1: Acrescente o campo que falta
Seção intitulada “Correção 1: Acrescente o campo que falta”Escolha esta na maioria das vezes. O campo existe por um motivo, então dê um valor de verdade para ele. Se você tem uma variável com o mesmo nome do campo, pode usar a forma abreviada User { name, email, active }.
struct User { name: String, email: String, active: bool,}
fn main() { let user = User { name: String::from("Ferris"), active: true, }; println!("{} <{}> ativo: {}", user.name, user.email, user.active);}Saída:
Ferris <[email protected]> ativo: trueCorreção 2: Derive Default e use ..Default::default()
Seção intitulada “Correção 2: Derive Default e use ..Default::default()”Escolha esta quando a struct tem muitos campos e a maioria deles tem um valor “vazio” óbvio, como configurações ou opções. Acrescente #[derive(Default)] à struct. Depois escreva só os campos que importam e termine com ..Default::default(). O .. quer dizer “pegue deste valor todos os campos que eu não escrevi”.
#[derive(Debug, Default)]struct Config { host: String, port: u16, debug: bool, timeout_secs: u64, retries: u8,}
fn main() { let config = Config { host: String::from("localhost"), port: 8080, ..Default::default() // ✅ debug, timeout_secs e retries recebem o padrão }; println!("{:?}", config);}Saída:
Config { host: "localhost", port: 8080, debug: false, timeout_secs: 0, retries: 0 }Os padrões derivados são 0 para números, false para bool, uma String vazia e None para um Option. Se 0 é um padrão ruim (um timeout de 0 segundos provavelmente é), escreva você mesmo um impl Default for Config com valores melhores. Veja Default: um valor inicial sensato.
Se você esquecer o #[derive(Default)], o erro vira E0277: the trait bound `Config: Default` is not satisfied (o trait Default não está implementado para Config), com help: consider annotating `Config` with `#[derive(Default)]` (considere anotar Config com #[derive(Default)]).
Correção 3: Escreva um construtor, new
Seção intitulada “Correção 3: Escreva um construtor, new”Escolha esta quando você cria a struct em vários lugares, ou quando alguns campos sempre começam do mesmo jeito. Coloque a struct completa numa função só e chame essa função em todos os outros lugares. Quando você acrescentar um campo depois, só precisa atualizar o new, e não cada chamada.
struct Player { name: String, score: u32, level: u8,}
impl Player { fn new(name: &str) -> Player { Player { name: name.to_string(), score: 0, // todo jogador novo começa com 0... level: 1, // ...no nível 1 } }}
fn main() { let ana = Player::new("Ana"); let mut bo = Player::new("Bo"); bo.score += 50; println!("{}: {} pontos, nível {}", ana.name, ana.score, ana.level); println!("{}: {} pontos, nível {}", bo.name, bo.score, bo.level);}Saída:
Ana: 0 pontos, nível 1Bo: 50 pontos, nível 1A struct dentro do new continua precisando de todos os campos, então um campo esquecido aparece ali como E0063. Tudo bem: você corrige uma vez só. Veja Funções construtoras.
Correção 4: Copie o resto de outro valor com ..outro
Seção intitulada “Correção 4: Copie o resto de outro valor com ..outro”Escolha esta quando você já tem um valor parecido e quer uma cópia com algumas mudanças. ..base pega de base todos os campos que você não escreveu:
#[derive(Debug, Clone)]struct Theme { name: String, font_size: u8, dark: bool,}
fn main() { let base = Theme { name: String::from("Padrão"), font_size: 14, dark: false };
// só `name` e `dark` mudam, o resto vem de `base` let night = Theme { name: String::from("Noturno"), dark: true, ..base };
// `..base` moveria `name` para fora de base, então clone para continuar usando base let large = Theme { font_size: 20, ..base.clone() };
println!("{:?}", night); println!("{:?}", large); println!("{:?}", base);}Saída:
Theme { name: "Noturno", font_size: 14, dark: true }Theme { name: "Padrão", font_size: 20, dark: false }Theme { name: "Padrão", font_size: 14, dark: false }Uma coisa importante: ..base move campos como String para fora de base. Em night não tem problema, porque escrevemos o nosso próprio name, então só os campos Copy (font_size) vieram de base. Em large, o name viria de base, então usamos ..base.clone() para base continuar utilizável. Se você pular o clone e usar base depois, recebe o E0382.
Quando campos Option ajudam
Seção intitulada “Quando campos Option ajudam”Às vezes um campo pode mesmo ficar vazio: um telefone que o usuário ainda não informou, um apelido, uma data de término. Faça esse campo ser um Option. Você ainda precisa escrevê-lo (o Rust não preenche None por você), mas agora None é um valor honesto e permitido. Veja Option.
#[derive(Debug, Default)]struct Contact { name: String, email: String, phone: Option<String>, // pode faltar nickname: Option<String>,}
fn main() { let a = Contact { name: String::from("Ana"), phone: None, // escrito por extenso: "ainda sem telefone" nickname: Some(String::from("Aninha")), }; // com Default, todo Option que você deixar de fora vira None let b = Contact { name: String::from("Bo"), ..Default::default() };
println!("{} telefone: {:?}, apelido: {:?}", a.name, a.phone, a.nickname); println!("{} e-mail: {:?}, telefone: {:?}", b.name, b.email, b.phone);}Saída:
Ana telefone: None, apelido: Some("Aninha")Bo e-mail: "", telefone: NoneRepare que b.email é "". Essa é a armadilha do Default: um campo obrigatório vira vazio sem avisar. Use Option só para coisas que são opcionais de verdade, e mantenha campos obrigatórios como email em tipos simples que você sempre preenche.
Onde você costuma ver esse erro
Seção intitulada “Onde você costuma ver esse erro”Logo depois de acrescentar um campo a uma struct. Você acrescenta created_at a User, e de repente todo User { ... } do projeto dá E0063. É o Rust ajudando você: cada um desses lugares é um ponto em que você precisa pensar. Um construtor new (Correção 3) deixa essa lista curta.
Variantes de enum com campos nomeados. Shape::Rectangle { width: 2.0 } dá missing field `height` in initializer of `Shape`. Repare que a mensagem diz o nome do enum, e não da variante. Correção: dê um valor para cada campo daquela variante. Veja Enums podem guardar dados.
Uma função que retorna uma struct. Em fn new_player(name: &str) -> Player { Player { name: name.to_string(), score: 0 } }, a seta aponta para Player dentro da função, com missing `level` (falta level). Correção: acrescente level nessa struct.
Erros relacionados
Seção intitulada “Erros relacionados”- E0560: struct has no field named x: o contrário, um campo que você escreveu e que a struct não tem. Um erro de digitação muitas vezes dá os dois ao mesmo tempo.
- E0559: variant has no field named x: o mesmo engano de nome errado em variantes de enum.
- E0277: trait bound not satisfied: você escreveu
..Default::default(), mas a struct não derivaDefault. - E0451: field is private: a struct vem de outro módulo e alguns campos são privados, então você não pode preenchê-los. Se você deixar um campo privado de fora, não recebe o E0063, e sim “cannot construct
Accountwith struct literal syntax due to private fields” (não é possível criarAccountcom a sintaxe literal por causa dos campos privados). De qualquer forma, use a funçãonewdo módulo. - E0382: use of moved value: você usou um valor depois que
..valormoveu os campos dele para fora. - Todos os erros do compilador explicados
Teste o que aprendeu
Seção intitulada “Teste o que aprendeu”Teste o que aprendeu
1. O rustc diz: missing fields a, b, c and 2 other fields. Quantos campos estão faltando?
2. A sua struct tem um campo Option<String> de que você ainda não precisa. O que você escreve nele?
3. Do que Config { port: 80, ..Default::default() } precisa para compilar?
Pontuação: 0 / 3
Para saber mais
Seção intitulada “Para saber mais”- E0063 — Rust error codes index (em inglês): a explicação oficial deste erro.
- Defining and Instantiating Structs — The Rust Book (em inglês): criação de structs, a forma abreviada de inicialização e a sintaxe de atualização.
Default— documentação da biblioteca padrão (em inglês):#[derive(Default)], como escrever o seu próprioimpl Defaulte o..Default::default().- Struct expressions — The Rust Reference (em inglês): as regras exatas de
Nome { campo: valor }e do..base. - Constructors — Rust API Guidelines (em inglês): por que o código Rust usa funções
newpara montar structs.