Pular para o conteúdo

Erro E0560 do Rust: struct has no field named X (campo desconhecido)

O E0560 quer dizer: você está criando uma struct com Nome { campo: valor }, e um dos campos que você escreveu não existe nessa struct. Normalmente é um erro de digitação, um campo que foi renomeado ou um campo que pertence a outra struct. O rustc muitas vezes diz o nome exato que você queria, então este é um dos erros mais rápidos de corrigir. (Esta página faz parte de Erros do compilador Rust explicados.)

error[E0560]: struct `User` has no field named `nmae`
--> src/main.rs:9:9
|
9 | nmae: String::from("Ferris"), // ❌ erro de digitação: o campo é `name`
| ^^^^ unknown field
|
help: a field with a similar name exists
|
9 - nmae: String::from("Ferris"), // ❌ erro de digitação: o campo é `name`
9 + name: String::from("Ferris"), // ❌ erro de digitação: o campo é `name`
|

Em português: “a struct User não tem nenhum campo chamado nmae”. O rótulo diz “campo desconhecido”, e a ajuda diz “existe um campo com um nome parecido”, mostrando a linha corrigida.

Este é o programa que gera o erro:

struct User {
name: String,
email: String,
active: bool,
}
fn main() {
let user = User {
nmae: String::from("Ferris"), // ❌ erro de digitação: o campo é `name`
email: String::from("[email protected]"),
active: true,
};
println!("{}", user.email);
}

A primeira linha diz o nome da struct (User) e o campo que você escreveu (nmae). O ^^^^ aponta para esse campo dentro do bloco User { ... }. O Rust comparou o nome com a lista de campos de struct User e não encontrou nenhum igual.

Embaixo da seta vem uma de três dicas. Cada uma diz uma coisa diferente:

  • help: a field with a similar name exists (existe um campo com um nome parecido): é erro de digitação. O rustc mostra a linha com o nome certo.
  • note: available fields are: `username` (os campos disponíveis são…): não há nenhum nome parecido. Esses são os campos que você ainda não preencheu.
  • note: all struct fields are already assigned (todos os campos da struct já foram preenchidos): você preencheu todos os campos de verdade, e este está sobrando.

Repare que o rustc não reclama também que falta o name. Corrija a digitação e os dois problemas somem de uma vez.

É como preencher um formulário de papel e escrever seu telefone num campo chamado “Fax”. O formulário não tem esse campo, então o atendente te devolve o papel.

Os campos de uma struct ficam fixos quando você escreve struct User { ... }. Toda vez que você cria um User, o Rust confere se você passou exatamente esses campos: nenhum faltando, nenhum sobrando, nenhum escrito errado. Veja Definindo e criando uma struct.

Isso pega bugs de verdade. Em JavaScript, { nmae: "Ferris" } cria sem avisar um objeto com a chave errada, e user.name vira undefined em algum lugar bem mais adiante. Em Rust, o erro de digitação não passa pelo compilador, então todo User do seu programa tem mesmo um name.

Escolha esta quando aparecer a field with a similar name exists. Use o nome da linha help:. Nomes de campos diferenciam maiúsculas de minúsculas, e o Rust usa snake_case, então userName e user_name são nomes diferentes.

Cuidado também com a forma abreviada de inicialização (field init shorthand): User { nmae, email } significa User { nmae: nmae, email: email }, então o nome da variável precisa ser igual ao nome do campo. Renomeie a variável ou escreva o campo por extenso: User { name: nmae, email }.

struct User {
name: String,
email: String,
active: bool,
}
fn main() {
let user = User {
name: String::from("Ferris"), // ✅ o nome real do campo
email: String::from("[email protected]"),
active: true,
};
println!("{} ({}) ativo: {}", user.name, user.email, user.active);
// forma abreviada: os nomes das variáveis são iguais aos dos campos
let name = String::from("Ada");
let email = String::from("[email protected]");
let other = User { name, email, active: false };
println!("{} ({}) ativo: {}", other.name, other.email, other.active);
}

Saída:

Ferris ([email protected]) ativo: true
Ada ([email protected]) ativo: false
▶ Experimente você mesmo

Correção 2: Use o novo nome do campo, ou acrescente o campo

Seção intitulada “Correção 2: Use o novo nome do campo, ou acrescente o campo”

Escolha esta quando não houver a dica de “nome parecido”. Muitas vezes a struct mudou: alguém renomeou name para username, ou um campo foi removido, mas este código ainda usa o antigo. O rustc lista o que sobrou:

error[E0560]: struct `User` has no field named `name`
--> src/main.rs:8:9
|
8 | name: String::from("Ferris"),
| ^^^^ `User` does not have this field
|
= note: available fields are: `username`

O rótulo diz “User não tem este campo”, e a nota lista os campos disponíveis.

Você tem duas escolhas honestas. Se a struct está certa, use o nome atual do campo. Se o seu código está certo e a struct precisa mesmo do campo, acrescente-o na definição da struct. Aqui, Config deu all struct fields are already assigned para debug, e a correção é acrescentar debug à struct:

struct User {
username: String, // renomeado de `name`: use o novo nome
email: String,
}
struct Config {
port: u16,
host: String,
debug: bool, // acrescentado à struct, porque o código precisa dele
}
fn main() {
let user = User {
username: String::from("ferris"),
email: String::from("[email protected]"),
};
println!("{} ({})", user.username, user.email);
let config = Config {
port: 8080,
host: String::from("localhost"),
debug: true,
};
println!("{}:{} debug={}", config.host, config.port, config.debug);
}

Saída:

localhost:8080 debug=true
▶ Experimente você mesmo

Se a struct vem de um crate que você acabou de atualizar, o campo pode ter sido renomeado na nova versão. Confira a struct no docs.rs (em inglês) para essa versão, ou o changelog do crate. Quando você acrescenta um campo a uma struct sua, todo lugar que a cria também precisa preenchê-lo. O rustc vai apontar cada um com o E0063 (veja abaixo).

Escolha esta quando o campo que você escreveu existe, só que em outra struct. Com duas structs parecidas, como um Product com title e um Customer com name, é fácil confundir:

error[E0560]: struct `Product` has no field named `name`
--> src/main.rs:13:9
|
13 | name: String::from("Keyboard"),
| ^^^^ `Product` does not have this field
|
= note: available fields are: `title`

Olhe a nota available fields. Se ela lista campos que você não esperava, você está montando a struct errada. Use o nome da struct certa, ou o nome do campo da struct que você queria:

struct Product {
title: String,
price: u32, // em centavos
}
struct Customer {
name: String,
email: String,
}
fn main() {
let keyboard = Product {
title: String::from("teclado"), // produtos têm `title`
price: 4900,
};
let buyer = Customer {
name: String::from("Ana"), // clientes têm `name`
email: String::from("[email protected]"),
};
println!("{} compra um {} por {} centavos", buyer.name, keyboard.title, keyboard.price);
println!("Recibo enviado para {}", buyer.email);
}

Saída:

Ana compra um teclado por 4900 centavos
Recibo enviado para [email protected]
▶ Experimente você mesmo

Escolha esta quando a struct é uma tuple struct, como struct Point(i32, i32);. Os campos dela não têm nome, então Point { x: 1, y: 2 } dá E0560 tanto para x quanto para y, com help: `Point` is a tuple struct, use the appropriate syntax (Point é uma tuple struct, use a sintaxe adequada) e a sugestão Point(/* i32 */, /* i32 */). Crie com parênteses, Point(1, 2), e leia com .0 e .1. Se preferir nomes, mude a definição para struct Point { x: i32, y: i32 }. Veja Quando usar uma tupla e quando usar uma struct.

O gêmeo do E0560 é o E0063: um campo que a struct tem, mas que você não preencheu. O Rust nunca preenche campos por você, então todo campo precisa de um valor:

error[E0063]: missing field `active` in initializer of `User`
--> src/main.rs:8:16
|
8 | let user = User {
| ^^^^ missing `active`

Em português: “falta o campo active na inicialização de User”. Com vários campos faltando, ele lista todos: missing fields `active`, `email` and `login_count` in initializer of `User`. Correção: dê um valor para cada campo. Se muitos campos têm valores padrão sensatos, derive Default e use a sintaxe de atualização de struct .. para preencher o resto:

#[derive(Debug, Default)]
struct Settings {
volume: u8,
dark_mode: bool,
language: String,
}
fn main() {
// todos os campos escritos por extenso
let full = Settings { volume: 80, dark_mode: false, language: String::from("pt") };
// só os campos que importam, o resto vem do Default
let quick = Settings { dark_mode: true, ..Default::default() };
// copia o resto de outro valor
let louder = Settings { volume: 100, ..full };
println!("{:?}", quick);
println!("{:?}", louder);
}

Saída:

Settings { volume: 0, dark_mode: true, language: "" }
Settings { volume: 100, dark_mode: false, language: "pt" }
▶ Experimente você mesmo

O padrão de um número é 0, de um bool é false, e de uma String é vazia. Se quiser outros valores padrão, escreva você mesmo um impl Default for Settings. Veja Default: um valor inicial sensato.

Dentro da sintaxe de atualização ... Settings { dark: true, ..defaults } também dá E0560. Aqui a nota lista todos os campos (available fields are: `volume`, `dark_mode`, `language`), e pode não haver a dica de “nome parecido” quando os nomes são diferentes demais. Correção: dark_mode: true.

Variantes de enum com campos nomeados. Para enum Shape { Circle { radius: f64 } }, escrever Shape::Circle { r: 2.0 } é o mesmo engano, mas o rustc usa outro código: E0559, variant `Shape::Circle` has no field named `r` (a variante Shape::Circle não tem campo chamado r), com a mesma nota available fields e as mesmas dicas de digitação. Correção: Shape::Circle { radius: 2.0 }. Veja Enums podem guardar dados.

Uma struct de outro módulo. Se o campo existe, mas não é pub, você recebe o E0451, “field balance of struct Account is private” (o campo balance da struct Account é privado). Correção: use o construtor do módulo, como Account::new(...). Veja Tudo é privado por padrão.

Teste o que aprendeu

1. O rustc diz note: all struct fields are already assigned. O que isso significa?

2. Você tem let nmae = ...; e escreve User { nmae, email }. Como corrigir?

3. Qual erro aparece quando você deixa um campo de fora, como User { name, email } sem active?

Pontuação: 0 / 3