Lewati ke konten

Error Rust E0063: missing field in initializer (field belum diisi)

E0063 artinya: kamu sedang membuat struct dengan Name { ... }, tapi tidak memberi nilai untuk setiap field-nya. Rust tidak pernah mengisi field untukmu, jadi setiap field butuh nilai, walaupun cuma 0, false, atau None. Pesannya menyebut nama field yang belum diisi, jadi kamu tahu persis apa yang harus ditambahkan. Ini salah satu error paling ramah di Rust. (Halaman ini bagian dari Penjelasan error compiler Rust.)

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

Artinya: field email belum diisi saat membuat User.

Ini program yang menghasilkan error tersebut:

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

Judul error-nya menyebut field yang belum diisi (email) dan struct-nya (User). Tanda ^^^^ menunjuk ke nama struct tempat kamu mulai membuatnya, bukan ke satu baris tertentu, karena masalahnya adalah sesuatu yang tidak ada.

Kalau ada beberapa field yang belum diisi, rustc menyebutkannya berurutan sesuai abjad. Kalau hanya dua atau tiga, semuanya ditampilkan:

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

Kalau empat atau lebih, rustc menampilkan tiga dan menghitung sisanya:

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” artinya masih ada satu field lagi. Lihat definisi struct Config untuk daftar lengkapnya.

Ini seperti formulir yang semua kotaknya wajib diisi. Kamu tidak bisa menyerahkannya dengan kotak “email” kosong, walaupun niatnya mau diisi nanti.

Di banyak bahasa, field yang tidak diisi diam-diam menjadi null, 0, atau string kosong. Lalu programmu berjalan dengan pengguna yang tidak punya email, dan rusak di tempat yang jauh, sering kali di production. Rust tidak punya null, dan tidak mengarang nilai di belakangmu. Sebuah User selalu punya email sungguhan. Lihat Mendefinisikan dan membuat struct.

Bukan berarti kamu harus mengetik setiap field setiap saat. Rust memberi cara singkat untuk bilang “pakai nilai default” atau “salin sisanya dari nilai lain ini”, seperti yang ditunjukkan perbaikan di bawah. Intinya, kamu yang memilih, dan pilihan itu tertulis di kode.

Perbaikan 1: Tambahkan field yang belum diisi

Section titled “Perbaikan 1: Tambahkan field yang belum diisi”

Pilih ini hampir setiap saat. Field itu ada karena suatu alasan, jadi beri nilai yang sungguhan. Kalau kamu punya variabel dengan nama yang sama dengan field-nya, kamu bisa memakai shorthand 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]"), // ✅ ditambahkan
active: true,
};
println!("{} <{}> aktif: {}", user.name, user.email, user.active);
}

Output:

Ferris <[email protected]> aktif: true
▶ Coba sendiri

Perbaikan 2: Derive Default dan pakai ..Default::default()

Section titled “Perbaikan 2: Derive Default dan pakai ..Default::default()”

Pilih ini kalau struct-nya punya banyak field dan sebagian besar punya nilai “kosong” yang jelas, seperti pengaturan atau opsi. Tambahkan #[derive(Default)] pada struct-nya. Lalu tulis hanya field yang kamu pedulikan, dan akhiri dengan ..Default::default(). Tanda .. artinya “ambil setiap field yang tidak kutulis dari nilai ini”.

#[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, dan retries mendapat nilai default
};
println!("{:?}", config);
}

Output:

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

Nilai default hasil derive adalah 0 untuk angka, false untuk bool, String kosong, dan None untuk Option. Kalau 0 bukan default yang bagus (timeout 0 detik mungkin memang bukan), tulis sendiri impl Default for Config dengan nilai yang lebih baik. Lihat Default: nilai awal yang masuk akal.

Kalau kamu lupa #[derive(Default)], error-nya berubah menjadi E0277: the trait bound `Config: Default` is not satisfied (trait bound Config: Default tidak terpenuhi), dengan help: consider annotating `Config` with `#[derive(Default)]` (coba tambahkan #[derive(Default)] pada Config).

Pilih ini kalau kamu membuat struct itu di banyak tempat, atau kalau beberapa field selalu dimulai dengan nilai yang sama. Taruh struct literal lengkapnya di satu fungsi, lalu panggil fungsi itu di tempat lain. Saat nanti kamu menambahkan field, kamu cukup memperbarui new, bukan setiap tempat pemanggilan.

struct Player {
name: String,
score: u32,
level: u8,
}
impl Player {
fn new(name: &str) -> Player {
Player {
name: name.to_string(),
score: 0, // setiap pemain baru mulai dari 0...
level: 1, // ...di level 1
}
}
}
fn main() {
let ana = Player::new("Ana");
let mut bo = Player::new("Bo");
bo.score += 50;
println!("{}: skor {}, level {}", ana.name, ana.score, ana.level);
println!("{}: skor {}, level {}", bo.name, bo.score, bo.level);
}

Output:

Ana: skor 0, level 1
Bo: skor 50, level 1
▶ Coba sendiri

Struct literal di dalam new tetap butuh setiap field, jadi field yang terlupa akan muncul di sana sebagai E0063. Tidak masalah: kamu cukup memperbaikinya sekali. Lihat Fungsi bergaya constructor.

Perbaikan 4: Salin sisanya dari nilai lain dengan ..other

Section titled “Perbaikan 4: Salin sisanya dari nilai lain dengan ..other”

Pilih ini kalau kamu sudah punya nilai yang mirip dan ingin salinannya dengan sedikit perubahan. ..base mengambil setiap field yang tidak kamu tulis dari base:

#[derive(Debug, Clone)]
struct Theme {
name: String,
font_size: u8,
dark: bool,
}
fn main() {
let base = Theme { name: String::from("Default"), font_size: 14, dark: false };
// hanya `name` dan `dark` yang berubah, sisanya diambil dari `base`
let night = Theme { name: String::from("Malam"), dark: true, ..base };
// `..base` akan memindahkan `name` keluar dari base, jadi clone dulu supaya base tetap bisa dipakai
let large = Theme { font_size: 20, ..base.clone() };
println!("{:?}", night);
println!("{:?}", large);
println!("{:?}", base);
}

Output:

Theme { name: "Malam", font_size: 14, dark: true }
Theme { name: "Default", font_size: 20, dark: false }
Theme { name: "Default", font_size: 14, dark: false }
▶ Coba sendiri

Satu hal yang perlu kamu tahu: ..base memindahkan (move) field seperti String keluar dari base. Di night ini tidak masalah, karena kita menulis name sendiri, jadi hanya field Copy (font_size) yang diambil dari base. Di large, name akan diambil dari base, jadi kita pakai ..base.clone() supaya base tetap bisa dipakai. Kalau kamu melewatkan clone dan memakai base setelahnya, kamu mendapat E0382.

Kadang sebuah field memang boleh kosong: nomor telepon yang belum diberikan pengguna, nama panggilan, tanggal selesai. Jadikan field itu Option. Kamu tetap harus menuliskannya (Rust tidak mengisi None untukmu), tapi sekarang None adalah nilai yang jujur dan diizinkan. Lihat Option.

#[derive(Debug, Default)]
struct Contact {
name: String,
email: String,
phone: Option<String>, // boleh kosong
nickname: Option<String>,
}
fn main() {
let a = Contact {
name: String::from("Ana"),
email: String::from("[email protected]"),
phone: None, // ditulis jelas: "belum ada nomor telepon"
nickname: Some(String::from("Annie")),
};
// dengan Default, setiap Option yang tidak kamu tulis menjadi None
let b = Contact { name: String::from("Bo"), ..Default::default() };
println!("{} telepon: {:?}, panggilan: {:?}", a.name, a.phone, a.nickname);
println!("{} email: {:?}, telepon: {:?}", b.name, b.email, b.phone);
}

Output:

Ana telepon: None, panggilan: Some("Annie")
Bo email: "", telepon: None
▶ Coba sendiri

Perhatikan bahwa b.email bernilai "". Inilah jebakan Default: field yang wajib diam-diam menjadi kosong. Pakai Option hanya untuk hal yang benar-benar opsional, dan biarkan field wajib seperti email memakai tipe biasa yang selalu kamu isi.

Tepat setelah kamu menambahkan field ke struct. Kamu menambahkan created_at ke User, dan tiba-tiba setiap User { ... } di proyekmu memberi E0063. Ini Rust sedang membantumu: setiap tempat itu perlu kamu pikirkan. Constructor new (Perbaikan 3) membuat daftar ini tetap pendek.

Varian enum dengan field bernama. Shape::Rectangle { width: 2.0 } memberi missing field `height` in initializer of `Shape`. Perhatikan bahwa pesannya menyebut enum-nya, bukan variannya. Perbaikannya: beri nilai untuk setiap field varian itu. Lihat Enum bisa menyimpan data.

Fungsi yang mengembalikan struct. Di fn new_player(name: &str) -> Player { Player { name: name.to_string(), score: 0 } }, tanda panahnya menunjuk ke Player di dalam fungsi, dengan missing `level`. Perbaikannya: tambahkan level ke literal itu.

  • E0560: struct has no field named x: kebalikannya, field yang kamu tulis tapi tidak dimiliki struct itu. Salah ketik sering memberi keduanya sekaligus.
  • E0559: variant has no field named x: kesalahan nama yang sama untuk varian enum.
  • E0277: trait bound not satisfied: kamu menulis ..Default::default() tapi struct-nya tidak derive Default.
  • E0451: field is private: struct-nya berasal dari modul lain dan sebagian field-nya private, jadi kamu tidak bisa mengisinya. Kalau kamu tidak menulis field private, kamu tidak mendapat E0063, melainkan “cannot construct Account with struct literal syntax due to private fields” (tidak bisa membuat Account dengan sintaks struct literal karena ada field private). Apa pun pesannya, pakai fungsi new dari modul itu.
  • E0382: use of moved value: kamu memakai sebuah nilai setelah ..value memindahkan field-nya keluar.
  • Semua error compiler: daftar lengkap halaman error.

Kuis singkat

1. rustc bilang: missing fields a, b, c and 2 other fields. Berapa field yang belum diisi?

2. Struct-mu punya field Option<String> yang belum kamu butuhkan. Apa yang kamu tulis untuknya?

3. Apa yang dibutuhkan Config { port: 80, ..Default::default() } supaya bisa di-compile?

Skor: 0 / 3