Salta ai contenuti

Errore Rust E0063: missing field in initializer (campo mancante)

E0063 significa: stai creando una struct con Name { ... }, ma non hai dato un valore a tutti i campi. Rust non compila mai i campi al posto tuo, quindi ognuno ha bisogno di un valore, anche solo 0, false o None. Il messaggio elenca per nome i campi mancanti, quindi sai esattamente cosa aggiungere. È uno degli errori più gentili di Rust. (Questa pagina fa parte di Errori del compilatore Rust spiegati.)

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

Il compilatore ti dice: «manca il campo email nell’inizializzazione di User».

Ecco il programma che lo provoca:

struct User {
name: String,
email: String,
active: bool,
}
fn main() {
let user = User {
name: String::from("Ferris"),
active: true,
// ❌ no `email`
};
println!("{}", user.name);
}

(Il commento dice: manca email.)

La prima riga nomina il campo mancante (email) e la struct (User). I ^^^^ indicano il nome della struct dove hai iniziato a costruirla, non una riga precisa, perché il problema è qualcosa che non c’è.

Quando mancano più campi, rustc li elenca in ordine alfabetico. Con due o tre li vedi tutti:

error[E0063]: missing fields `debug`, `retries` and `timeout_secs` in initializer of `Config`

Con quattro o più, ne mostra tre e conta gli altri:

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» vuol dire che ce n’è ancora uno. Guarda la definizione di struct Config per vedere l’elenco completo.

È come un modulo in cui ogni casella è obbligatoria. Non puoi consegnarlo con la casella «email» vuota, anche se pensavi di compilarla dopo.

In molti linguaggi un campo mancante diventa in silenzio null, 0 o una stringa vuota. Poi il tuo programma gira con un utente senza email, e si rompe da qualche parte lontano, spesso in produzione. Rust non ha null e non inventa valori alle tue spalle. Un User ha sempre una email vera. Vedi Struct.

Questo non vuol dire che devi scrivere tutti i campi ogni volta. Rust ti dà modi brevi per dire «usa i valori predefiniti» o «copia il resto da quest’altro valore», come mostrano le soluzioni qui sotto. Il punto è che sei tu a scegliere, e la scelta è scritta nel codice.

Scegli questa strada quasi sempre. Il campo c’è per un motivo, quindi dagli un valore vero. Se hai una variabile con lo stesso nome del campo, puoi usare la forma abbreviata User { name, email, active }.

struct User {
name: String,
email: String,
active: bool,
}
fn main() {
let user = User {
name: String::from("Ferris"),
email: String::from("[email protected]"), // ✅ aggiunto
active: true,
};
println!("{} <{}> attivo: {}", user.name, user.email, user.active);
}

Output:

Ferris <[email protected]> attivo: true
▶ Provalo tu

Soluzione 2: deriva Default e usa ..Default::default()

Sezione intitolata “Soluzione 2: deriva Default e usa ..Default::default()”

Scegli questa strada quando la struct ha molti campi e quasi tutti hanno un valore «vuoto» ovvio, come impostazioni o opzioni. Aggiungi #[derive(Default)] alla struct. Poi scrivi solo i campi che ti interessano e chiudi con ..Default::default(). Il .. vuol dire «prendi da questo valore tutti i campi che non ho scritto».

#[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 prendono i valori predefiniti
};
println!("{:?}", config);
}

Output:

Config { host: "localhost", port: 8080, debug: false, timeout_secs: 0, retries: 0 }
▶ Provalo tu

I valori predefiniti derivati sono 0 per i numeri, false per bool, una String vuota e None per un Option. Se 0 è un cattivo valore predefinito (un timeout di 0 secondi probabilmente lo è), scrivi tu impl Default for Config con valori migliori. Vedi Trait comuni.

Se dimentichi #[derive(Default)], l’errore diventa E0277: the trait bound `Config: Default` is not satisfied, con help: consider annotating `Config` with `#[derive(Default)]`.

Scegli questa strada quando crei la struct in molti punti, o quando alcuni campi partono sempre allo stesso modo. Metti il letterale completo della struct in una sola funzione, e chiama quella funzione ovunque. Quando più avanti aggiungi un campo, aggiorni solo new, non ogni chiamata.

struct Player {
name: String,
score: u32,
level: u8,
}
impl Player {
fn new(name: &str) -> Player {
Player {
name: name.to_string(),
score: 0, // ogni nuovo giocatore parte da 0...
level: 1, // ...al livello 1
}
}
}
fn main() {
let ana = Player::new("Ana");
let mut bo = Player::new("Bo");
bo.score += 50;
println!("{}: punteggio {}, livello {}", ana.name, ana.score, ana.level);
println!("{}: punteggio {}, livello {}", bo.name, bo.score, bo.level);
}

Output:

Ana: punteggio 0, livello 1
Bo: punteggio 50, livello 1
▶ Provalo tu

Il letterale dentro new ha comunque bisogno di tutti i campi, quindi un campo dimenticato compare lì come E0063. Va bene così: lo correggi una volta sola. Vedi Struct.

Soluzione 4: copia il resto da un altro valore con ..altro

Sezione intitolata “Soluzione 4: copia il resto da un altro valore con ..altro”

Scegli questa strada quando hai già un valore simile e ne vuoi una copia con qualche modifica. ..base prende da base tutti i campi che non hai scritto:

#[derive(Debug, Clone)]
struct Theme {
name: String,
font_size: u8,
dark: bool,
}
fn main() {
let base = Theme { name: String::from("Predefinito"), font_size: 14, dark: false };
// cambiano solo `name` e `dark`, il resto arriva da `base`
let night = Theme { name: String::from("Notte"), dark: true, ..base };
// `..base` sposterebbe `name` fuori da base, quindi clonalo per continuare a usare base
let large = Theme { font_size: 20, ..base.clone() };
println!("{:?}", night);
println!("{:?}", large);
println!("{:?}", base);
}

Output:

Theme { name: "Notte", font_size: 14, dark: true }
Theme { name: "Predefinito", font_size: 20, dark: false }
Theme { name: "Predefinito", font_size: 14, dark: false }
▶ Provalo tu

Una cosa da sapere: ..base sposta fuori da base i campi come String. In night va bene, perché abbiamo scritto un nostro name, quindi da base sono arrivati solo i campi Copy (font_size). In large, name arriverebbe da base, quindi usiamo ..base.clone() per poter continuare a usare base. Se salti il clone e usi base dopo, ottieni E0382.

A volte un campo può davvero essere vuoto: un numero di telefono che l’utente non ha ancora dato, un soprannome, una data di fine. Rendi quel campo un Option. Devi comunque scriverlo (Rust non mette None al posto tuo), ma ora None è un valore onesto e permesso. Vedi Option.

#[derive(Debug, Default)]
struct Contact {
name: String,
email: String,
phone: Option<String>, // può mancare
nickname: Option<String>,
}
fn main() {
let a = Contact {
name: String::from("Ana"),
email: String::from("[email protected]"),
phone: None, // scritto per esteso: «ancora nessun telefono»
nickname: Some(String::from("Annie")),
};
// con Default, ogni Option che ometti diventa None
let b = Contact { name: String::from("Bo"), ..Default::default() };
println!("{} telefono: {:?}, soprannome: {:?}", a.name, a.phone, a.nickname);
println!("{} email: {:?}, telefono: {:?}", b.name, b.email, b.phone);
}

Output:

Ana telefono: None, soprannome: Some("Annie")
Bo email: "", telefono: None
▶ Provalo tu

Nota che b.email è "". È questa la trappola di Default: un campo obbligatorio diventa vuoto senza far rumore. Usa Option solo per le cose davvero facoltative, e tieni i campi obbligatori come email con tipi normali, da compilare sempre.

Subito dopo aver aggiunto un campo a una struct. Aggiungi created_at a User, e all’improvviso ogni User { ... } del progetto dà E0063. È Rust che ti aiuta: ogni punto è uno a cui devi pensare. Un costruttore new (Soluzione 3) tiene corto questo elenco.

Varianti di enum con campi nominati. Shape::Rectangle { width: 2.0 } dà missing field `height` in initializer of `Shape`. Nota che il messaggio nomina l’enum, non la variante. Soluzione: dai un valore a ogni campo di quella variante. Vedi Enum.

Una funzione che restituisce una struct. In fn new_player(name: &str) -> Player { Player { name: name.to_string(), score: 0 } }, la freccia indica Player dentro la funzione, con missing `level`. Soluzione: aggiungi level a quel letterale.

Verifica veloce

1. rustc dice: missing fields a, b, c and 2 other fields. Quanti campi mancano?

2. La tua struct ha un campo Option<String> che per ora non ti serve. Cosa scrivi?

3. Di cosa ha bisogno Config { port: 80, ..Default::default() } per compilare?

Punteggio: 0 / 3