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.)
Il messaggio di errore
Sezione intitolata “Il messaggio di errore”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.)
Cosa significa
Sezione intitolata “Cosa significa”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.
Perché Rust si comporta così
Sezione intitolata “Perché Rust si comporta così”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.
Come risolverlo
Sezione intitolata “Come risolverlo”Soluzione 1: aggiungi il campo mancante
Sezione intitolata “Soluzione 1: aggiungi il campo mancante”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"), active: true, }; println!("{} <{}> attivo: {}", user.name, user.email, user.active);}Output:
Ferris <[email protected]> attivo: trueSoluzione 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 }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)]`.
Soluzione 3: scrivi un costruttore, new
Sezione intitolata “Soluzione 3: scrivi un costruttore, new”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 1Bo: punteggio 50, livello 1Il 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 }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.
Quando aiutano i campi Option
Sezione intitolata “Quando aiutano i campi Option”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"), 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: NoneNota 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.
Dove lo incontri di solito
Sezione intitolata “Dove lo incontri di solito”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.
Errori correlati
Sezione intitolata “Errori correlati”- E0560: struct has no field named x: l’opposto, un campo che hai scritto e che la struct non ha. Un errore di battitura spesso li dà entrambi insieme.
- E0559: variant has no field named x: lo stesso errore di nome sbagliato per le varianti di enum.
- E0277: trait bound not satisfied: hai scritto
..Default::default()ma la struct non derivaDefault. - E0451: field is private: la struct arriva da un altro modulo e alcuni campi sono privati, quindi non puoi compilarli. Se ometti un campo privato, non ottieni E0063 ma «cannot construct
Accountwith struct literal syntax due to private fields». In entrambi i casi, usa la funzionenewdel modulo. - E0382: use of moved value: hai usato un valore dopo che
..valorene ha spostato fuori i campi. - Tutti gli errori del compilatore spiegati
Verifica veloce
Sezione intitolata “Verifica veloce”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
Per approfondire
Sezione intitolata “Per approfondire”- E0063 — Rust error codes index (in inglese): la spiegazione ufficiale di questo errore.
- Defining and Instantiating Structs — The Rust Book (in inglese): letterali di struct, forma abbreviata dei campi e sintassi di aggiornamento.
Default— libreria standard di Rust (in inglese):#[derive(Default)], come scrivere il tuoimpl Default, e..Default::default().- Struct expressions — The Rust Reference (in inglese): le regole esatte di
Name { field: value }e di..base. - Constructors — Rust API Guidelines (in inglese): perché il codice Rust usa funzioni
newper costruire le struct.