Lewati ke konten

Error Rust E0616: field of struct is private (field privat)

E0616 artinya: field yang kamu minta memang ada, tapi field itu privat di modul tempat struct-nya didefinisikan. Kamu boleh memegang struct-nya, hanya saja tidak boleh mengintip ke dalamnya. Error ini dialami semua orang yang pertama kali memindahkan struct ke modulnya sendiri, dan semua orang yang mengetik v.len padahal maksudnya v.len(). Perbaikannya biasanya cukup dengan memanggil method. Halaman ini bagian dari Penjelasan error compiler Rust.

error[E0616]: field `balance` of struct `Account` is private
--> src/main.rs:16:50
|
16 | println!("{} has {}", account.owner, account.balance); // ❌ field privat
| ^^^^^^^ private field

Compiler bilang field balance milik struct Account itu privat, dan panahnya menunjuk ke field tersebut.

Ini program yang menghasilkan error tersebut:

mod bank {
pub struct Account {
pub owner: String,
balance: u64, // privat
}
impl Account {
pub fn new(owner: &str) -> Account {
Account { owner: owner.to_string(), balance: 0 }
}
}
}
fn main() {
let account = bank::Account::new("Ferris");
println!("{} has {}", account.owner, account.balance); // ❌ field privat
}

Error yang sama muncul dalam beberapa variasi:

Apa yang kamu tulis Apa kata rustc Perbaikan
account.balance field `balance` of struct `Account` is private Perbaikan 2 atau 3
scores.len pada Vec field `len` of struct `Vec` is private, ditambah help: a method `len` also exists, call it with parentheses (ada method len, panggil dengan tanda kurung) Perbaikan 1
timeout.secs pada Duration field `secs` of struct `Duration` is private Perbaikan 1 (as_secs())
account.balance = 500 E0616 yang sama: menulis juga diblokir Perbaikan 2

Panahnya menunjuk nama field sesudah titik. account.owner di baris yang sama tidak bermasalah, karena owner ditandai pub. balance tidak, jadi hanya kode di dalam mod bank yang boleh membaca atau mengubahnya.

Perhatikan bahwa Account sendiri sudah pub. Bagian inilah yang mengejutkan banyak orang: membuat struct menjadi publik tidak membuat field-nya ikut publik. Setiap field butuh pub-nya sendiri, atau tetap privat.

Bayangkan sebuah bank. Kamu boleh masuk, dan siapa pun bisa melihat nama pemilik rekeningmu. Tapi kamu tidak bisa masuk ke balik meja lalu membuka brankas untuk menghitung uangnya. Kamu minta tolong ke teller, dan teller mengikuti aturan bank.

Di Rust, semuanya privat secara default: fungsi, modul, dan juga field struct (lihat Modul). Privasi ditentukan oleh modul, bukan oleh tipe. Semua kode di dalam mod bank boleh menyentuh balance, dan kode di luarnya tidak.

Tujuannya supaya sebuah struct bisa menjaga aturannya sendiri. Misalnya saldo bank tidak boleh negatif. Kalau setiap bagian program bisa menulis account.balance = ..., bagian mana pun bisa melanggar aturan itu, dan kamu harus menyisir seluruh kode untuk mencari pelakunya. Kalau field-nya privat, hanya segelintir method di dalam mod bank yang bisa mengubahnya. Periksa aturannya di sana, dan aturan itu berlaku di mana-mana. Ide ini disebut encapsulation (enkapsulasi).

Standard library juga melakukan hal yang sama. Vec punya field privat untuk panjangnya dan buffer memorinya. Kalau kamu bisa menulis v.len = 100 pada vektor yang hanya berisi 3 item, membaca v[50] akan membaca memori acak. Menjaga len tetap privat itulah yang membuat Vec aman dipakai.

Perbaikan 1: Panggil method-nya, bukan membaca field-nya

Section titled “Perbaikan 1: Panggil method-nya, bukan membaca field-nya”

Pilih ini kalau struct-nya berasal dari standard library atau crate lain. Kamu tidak bisa mengubah kode mereka, dan mereka selalu menyediakan method untuk hal-hal yang boleh kamu lihat. Kalau rustc bilang help: a method ... also exists, tambahkan ():

use std::time::Duration;
fn main() {
let scores = vec![10, 20, 30];
println!("{} skor", scores.len());
let timeout = Duration::from_secs(90);
println!("Timeout: {} detik", timeout.as_secs());
}

Output:

3 skor
Timeout: 90 detik
▶ Coba sendiri

Nama method-nya tidak selalu sama dengan nama field-nya (secs dibaca dengan as_secs()). Lihat halaman tipe itu di docs.rs, atau biarkan editor-mu menampilkan daftar method setelah kamu mengetik titik.

Perbaikan 2: Tambahkan getter, dan method yang mengikuti aturan

Section titled “Perbaikan 2: Tambahkan getter, dan method yang mengikuti aturan”

Pilih ini kalau struct-nya milikmu sendiri dan field-nya punya aturan yang perlu dijaga. Biarkan field-nya privat, tambahkan pub fn yang mengembalikan nilainya (sebuah getter), dan ubah field itu hanya lewat method yang memeriksa aturannya:

mod bank {
pub struct Account {
pub owner: String,
balance: i64, // privat: hanya modul ini yang bisa mengubahnya
}
impl Account {
pub fn new(owner: &str) -> Account {
Account { owner: owner.to_string(), balance: 0 }
}
// Getter: siapa saja boleh membaca saldonya.
pub fn balance(&self) -> i64 {
self.balance
}
pub fn deposit(&mut self, amount: i64) {
if amount > 0 {
self.balance += amount;
}
}
// Aturannya ada di sini: saldo tidak pernah di bawah nol.
pub fn withdraw(&mut self, amount: i64) -> Result<(), String> {
if amount > self.balance {
return Err(format!("hanya tersedia {}", self.balance));
}
self.balance -= amount;
Ok(())
}
}
}
fn main() {
let mut account = bank::Account::new("Ferris");
account.deposit(100);
println!("Saldo {}: {}", account.owner, account.balance());
match account.withdraw(500) {
Ok(()) => println!("Berhasil menarik 500"),
Err(e) => println!("Tidak bisa menarik 500: {e}"),
}
println!("Saldo masih {}", account.balance());
}

Output:

Saldo Ferris: 100
Tidak bisa menarik 500: hanya tersedia 100
Saldo masih 100
▶ Coba sendiri

Rust membolehkan method dan field punya nama yang sama, jadi balance() adalah nama yang lazim untuk getter-nya (bukan get_balance()). Begitu getter-nya ada, rustc bahkan menyarankannya: help: a method `balance` also exists, call it with parentheses. deposit dan withdraw adalah setter-mu: keduanya mengubah field, tapi hanya dengan cara yang diizinkan aturan. Selengkapnya tentang method di Struct.

Perbaikan 3: Jadikan field-nya pub kalau datanya sederhana

Section titled “Perbaikan 3: Jadikan field-nya pub kalau datanya sederhana”

Pilih ini kalau nilai apa pun boleh dan tidak ada hal lain yang bergantung pada field itu. Sebuah titik di grid, sebuah warna, atau struct pengaturan tidak punya aturan yang perlu dijaga. Getter di situ hanya menambah ketikan:

mod geometry {
pub struct Point {
pub x: i32,
pub y: i32,
}
}
fn main() {
let mut p = geometry::Point { x: 3, y: 4 };
p.x += 1;
println!("Titik di ({}, {})", p.x, p.y);
}

Output:

Titik di (4, 4)
▶ Coba sendiri

Kalau hanya kodemu sendiri yang boleh melihat field itu, tulis pub(crate) x: i32 (semua modul di crate ini) atau pub(super) x: i32 (hanya modul induknya). Di sebuah program, keduanya berperilaku seperti pub; di sebuah library, keduanya menjaga field itu tetap di luar API publikmu. Halaman E0603 punya tabel semua tingkatannya.

Jadi, langsung jadikan pub saja? Tanyakan: “Apakah ada nilai tertentu untuk field ini, atau perubahan pada field ini saja, yang bisa membuat struct-nya salah?” Saldo negatif, len yang tidak cocok dengan datanya, total yang tidak lagi sama dengan jumlah item-nya: biarkan yang seperti itu privat dan pakai Perbaikan 2. Kalau jawabannya “tidak, nilai apa pun boleh”, pub adalah pilihan yang jujur.

len pada Vec. Kamu menulis scores.len dan mendapat field `len` of struct `Vec` is private. Itu karena Vec memang punya field privat bernama len. Perbaikannya scores.len(). Detail lucunya: name.len pada String memberi error lain, E0615 (attempted to take value of method, mencoba mengambil nilai dari method), karena String tidak punya field dengan nama itu. Perbaikannya sama.

Mengubah field dari luar. account.balance = 500; memberi E0616 yang sama. Menulis juga diblokir. Jangan jadikan field-nya pub hanya supaya bisa diubah; tambahkan method seperti deposit yang melakukan perubahan itu sekaligus memeriksanya.

Setelah memindahkan struct ke modul atau file-nya sendiri. Kode di main.rs sudah berbulan-bulan memakai user.email. Lalu kamu memindahkan User ke src/user.rs, dan semua akses field langsung rusak. Field yang tadinya tidak bermasalah sekarang privat di mod user. Tambahkan pub pada field yang berisi data sederhana, dan getter untuk sisanya.

Test. Blok #[cfg(test)] mod tests di dalam file yang sama adalah modul anak, jadi ia boleh membaca field privat. Test di folder tests/ berada di luar crate-mu dan hanya bisa memakai API pub, sama seperti pengguna lain.

  • E0603: function `x` is private. Ide yang sama untuk fungsi, struct, dan modul.
  • E0451: field privat yang sama, tapi saat membuat struct dengan Account { ... }.
  • E0624: method `x` is private. Method-nya (atau new) juga butuh pub.
  • E0609: no field `x` on type `T` . Field-nya sama sekali tidak ada (sering karena salah ketik).
  • E0615: attempted to take value of method. Kamu menulis x.len padahal maksudnya x.len().
  • Semua error compiler: daftar lengkap halaman error.

Kuis singkat

1. pub struct Account { balance: u64 } ada di dalam mod bank. Bisakah main membaca account.balance?

2. Kamu mendapat `field len of struct Vec is private`. Apa perbaikannya?

3. Struct Score punya field points yang harus tetap di antara 0 dan 100. Desain apa yang paling baik?

Skor: 0 / 3