Lewati ke konten

Error Rust E0603: function, struct or module is private (item privat)

E0603 sebenarnya kabar baik yang menyamar: Rust sudah menemukan fungsi, struct, atau modul yang kamu minta. Ia hanya tidak boleh memberikannya kepadamu, karena item itu privat. Semua yang ada di modul Rust bersifat privat sampai kamu bilang sebaliknya, jadi error ini muncul pertama kali pada hampir semua orang yang mulai memecah kode ke beberapa modul. Perbaikannya biasanya cuma satu kata: pub. Halaman ini bagian dari Penjelasan error compiler Rust.

error[E0603]: function `apply_discount` is private
--> src/main.rs:8:26
|
8 | let total = billing::apply_discount(200); // ❌ private
| ^^^^^^^^^^^^^^ private function
|
note: the function `apply_discount` is defined here
--> src/main.rs:2:5
|
2 | fn apply_discount(price: u32) -> u32 { // no `pub`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Compiler bilang fungsi apply_discount itu privat, dan note: menunjukkan di mana fungsi itu didefinisikan.

Ini program yang menghasilkan error tersebut:

mod billing {
fn apply_discount(price: u32) -> u32 { // no `pub`
price * 90 / 100
}
}
fn main() {
let total = billing::apply_discount(200); // ❌ private
println!("Total: {total}");
}

Baris pertama menyebut jenis item-nya, jadi error yang sama muncul dalam beberapa variasi:

Apa kata baris pertama Apa yang biasanya salah Perbaikan
function `apply_discount` is private fn-nya tidak punya pub Perbaikan 1 atau 2
struct `Order` is private struct-nya tidak punya pub Perbaikan 1
module `prices` is private ada mod di path yang tidak punya pub Perbaikan 1 atau 3
function import `price_of` is private kamu menjangkau item lewat use biasa di dalam modul lain Perbaikan 3
tuple struct constructor `Percent` is private struct-nya pub, tapi field-nya tidak Perbaikan 4

Baca kedua panahnya. Panah pertama (baris 8) adalah tempat kamu memakai item itu. Panah note: (baris 2) adalah tempat item itu didefinisikan. Rust bilang: “Aku melihat apply_discount di sana, tapi fungsi itu tidak pernah ditandai untuk dibagikan, jadi kode di luar billing tidak boleh memanggilnya.”

File-nya tidak berpengaruh. Kalau billing ada di src/billing.rs, kamu mendapat error yang sama, hanya saja note:-nya menunjuk src/billing.rs:1:1.

Bayangkan sebuah gedung kantor. Setiap modul adalah ruangan yang punya pintu. Item privat adalah alat yang tetap tinggal di ruangannya: orang di dalam ruangan itu (dan di ruangan-ruangan kecil di dalamnya) boleh memakainya, tapi orang dari lorong tidak. pub menaruh alat itu di rak di lorong.

Rust membuat semuanya privat secara default: fungsi, struct, field struct, modul, bahkan import use. Kamu memilih sendiri apa yang dibagikan dengan pub. Pelajaran Modul menunjukkan hal ini sejak awal.

Alasannya adalah keamanan untuk dirimu di masa depan. Apa pun yang pub menjadi sebuah janji: kode lain mungkin bergantung padanya, jadi mengubahnya bisa merusak kode itu. Item privat bebas diubah, diganti namanya, atau dihapus, dan compiler menjamin tidak ada kode di luar yang bergantung padanya. Fungsi pembantu kecil tetap jadi pembantu, dan sebuah struct bisa menjaga aturannya sendiri (misalnya “saldo tidak pernah negatif”), karena tidak ada yang bisa menyentuh field-nya secara langsung.

Satu detail lagi: privasi diperiksa di setiap langkah path. shop::prices::price_of hanya jalan kalau prices terlihat olehmu dan price_of juga terlihat olehmu. pub fn di dalam modul privat tetap tidak bisa dijangkau.

Perbaikan 1: Tambahkan pub pada item-nya (dan pada setiap modul di path-nya)

Section titled “Perbaikan 1: Tambahkan pub pada item-nya (dan pada setiap modul di path-nya)”

Pilih ini kalau item-nya memang dimaksudkan untuk dipakai dari luar modulnya. Hampir selalu, inilah perbaikan yang tepat:

mod billing {
pub fn apply_discount(price: u32) -> u32 {
price * 90 / 100
}
}
fn main() {
let total = billing::apply_discount(200);
println!("Total: {total}");
}

Output:

Total: 180
▶ Coba sendiri

Kalau error-nya bilang module `prices` is private, pub yang kurang ada di modulnya: tulis pub mod prices { ... }. rustc juga menandai kasus ini dengan label kedua, function `price_of` is not publicly re-exported (fungsi price_of tidak di-re-export secara publik). Kalau modulnya di file terpisah, pub ditulis di baris deklarasinya: pub mod prices;.

Untuk struct, pub struct Order membuat tipe-nya publik, tapi setiap field tetap butuh pub sendiri kalau kode di luar perlu membaca atau mengisinya. Selengkapnya di Perbaikan 4.

Perbaikan 2: Pakai pub(crate) atau pub(super) untuk “hanya kodeku”

Section titled “Perbaikan 2: Pakai pub(crate) atau pub(super) untuk “hanya kodeku””

Pilih ini kalau item-nya perlu dibagikan, tapi tidak ke seluruh dunia. pub punya beberapa tingkat, dari yang paling sempit sampai paling luas:

Kamu menulis Siapa yang boleh memakai item-nya
tidak ada (privat) modulnya sendiri, dan modul-modul di dalamnya
pub(super) ditambah modul induknya
pub(crate) semua kode di crate ini
pub semua orang, termasuk crate lain yang bergantung pada crate-mu

Di sebuah program (binary), pub(crate) dan pub hampir sama saja. Bedanya terasa di library: pub(crate) membuat modul-modulmu bisa berbagi fungsi pembantu tanpa menjadikannya bagian dari API publik library.

mod shop {
// Semua kode di crate ini boleh memanggil fungsi ini.
pub(crate) fn store_name() -> &'static str {
"Ferris Fruits"
}
pub mod receipt {
// Hanya modul induknya, `shop`, yang boleh memanggil fungsi pembantu ini.
pub(super) fn line(item: &str, price: u32) -> String {
format!("{item}: {price}")
}
}
pub fn print_receipt(items: &[(&str, u32)]) {
println!("== {} ==", store_name());
for (item, price) in items {
println!("{}", receipt::line(item, *price));
}
}
}
fn main() {
println!("Selamat datang di {}", shop::store_name());
shop::print_receipt(&[("apple", 3), ("pear", 5)]);
// shop::receipt::line("apple", 3); // ❌ E0603: `line` hanya untuk `shop`
}

Output:

Selamat datang di Ferris Fruits
== Ferris Fruits ==
apple: 3
pear: 5
▶ Coba sendiri

Hapus // di depan baris terakhir, dan kamu akan mendapat function `line` is private, meskipun tertulis pub(super). main bukan induk dari receipt, jadi pintunya tetap tertutup.

Pilih ini kalau modul bagian dalamnya adalah detail internal, tapi ada satu item di dalamnya yang perlu mudah dijangkau. Biarkan modulnya tetap privat, dan taruh item-nya di path yang lebih pendek dan publik:

mod shop {
mod prices {
// tetap privat: cara harga disimpan adalah urusan shop
pub fn price_of(item: &str) -> u32 {
if item == "apple" { 3 } else { 5 }
}
}
pub use prices::price_of; // sekarang bisa dijangkau sebagai shop::price_of
}
fn main() {
println!("Harga apel: {}", shop::price_of("apple"));
println!("Harga pir: {}", shop::price_of("pear"));
}

Output:

Harga apel: 3
Harga pir: 5
▶ Coba sendiri

Ini juga perbaikan untuk function import `price_of` is private. use prices::price_of; biasa di dalam shop adalah jalan pintas khusus untuk shop; seperti yang lainnya, use juga privat. pub use mengubah jalan pintas itu menjadi pintu publik. Crate besar melakukan ini terus-menerus, sehingga kamu bisa menulis serde::Serialize tanpa perlu tahu di modul dalam mana ia sebenarnya berada.

Perbaikan 4: Tambahkan pub fn new, bukan membuat field-nya publik

Section titled “Perbaikan 4: Tambahkan pub fn new, bukan membuat field-nya publik”

Pilih ini kalau error-nya tentang field sebuah struct atau constructor-nya. Di sini struct-nya pub, tapi field-nya tidak:

mod billing {
pub struct Percent(u8);
}
fn main() {
let discount = billing::Percent(150); // ❌ private constructor
}
error[E0603]: tuple struct constructor `Percent` is private
--> src/main.rs:6:29
|
2 | pub struct Percent(u8);
| -- a constructor is private if any of the fields is private
...
6 | let discount = billing::Percent(150); // ❌ private constructor
| ^^^^^^^ private tuple struct constructor
|
help: consider making the field publicly accessible
|
2 | pub struct Percent(pub u8);
| +++

Compiler menjelaskan bahwa constructor menjadi privat kalau ada satu saja field yang privat, lalu menyarankan untuk membuat field-nya publik.

rustc menyarankan pub u8, dan untuk tipe data biasa itu tidak masalah. Tapi lihat nilainya: 150 persen! Sering kali field privat itu memang tujuannya. Modulnya ingin memeriksa nilai sebelum sebuah Percent dibuat. Beri ia constructor publik yang melakukan pemeriksaan itu:

mod billing {
pub struct Percent(u8);
impl Percent {
pub fn new(value: u8) -> Option<Percent> {
if value <= 100 { Some(Percent(value)) } else { None }
}
pub fn apply(&self, price: u32) -> u32 {
price * (100 - self.0 as u32) / 100
}
}
}
fn main() {
let ten = billing::Percent::new(10).unwrap();
println!("200 dengan diskon 10%: {}", ten.apply(200));
println!("Apakah 150% boleh? {}", billing::Percent::new(150).is_some());
}

Output:

200 dengan diskon 10%: 180
Apakah 150% boleh? false
▶ Coba sendiri

Sekarang setiap Percent di seluruh program dijamin bernilai antara 0 dan 100, dan apply tidak akan pernah underflow. Ingat, new sendiri juga butuh pub; method privat menghasilkan error lain, E0624 (associated function `new` is private). Lihat Struct untuk penjelasan lebih lanjut tentang constructor.

Package yang punya main.rs sekaligus lib.rs. Keduanya adalah dua crate terpisah, dan main.rs memakai library-nya dari luar. Kalau lib.rs menulis mod inventory;, maka use shop::inventory::count_items; di main.rs gagal:

error[E0603]: module `inventory` is private
--> src/main.rs:1:11
|
1 | use shop::inventory::count_items;
| ^^^^^^^^^ private module

Compiler bilang modul inventory privat, jadi main.rs tidak bisa menjangkaunya.

Perbaikannya: tulis pub mod inventory; di lib.rs dan pub fn count_items di modulnya. Hati-hati: pub(crate) tidak cukup di sini. Bagi library, main.rs adalah crate lain, jadi pub(crate) fn tetap menghasilkan function `count_items` is private. Lihat Cargo dan crate.

Field struct yang privat. Kasus ini punya kode error sendiri. Membuat struct yang punya field privat menghasilkan E0451, dan membaca field privat menghasilkan E0616:

error[E0451]: field `balance` of struct `Account` is private
error[E0616]: field `balance` of struct `Account` is private

Keduanya berarti field balance milik struct Account itu privat.

Perbaikannya: pilihannya sama seperti Perbaikan 4. Tambahkan pub pada field-nya kalau siapa saja boleh mengubahnya, atau biarkan privat lalu tambahkan pub fn new(...) ditambah getter seperti pub fn balance(&self) -> u64.

Fungsi yang kamu temukan di source code sebuah crate. Kamu membaca sebuah crate di GitHub, menemukan fungsi pembantu yang pas, lalu mendapat E0603 saat memanggilnya. Kalau pembuat crate itu tidak menjadikannya pub, kamu tidak bisa memakainya, dan mereka bisa mengubahnya kapan saja. Cari cara publik untuk melakukan hal yang sama di halaman crate itu di docs.rs; hanya item pub yang tampil di sana.

  • E0432: unresolved import. Item-nya sama sekali tidak ditemukan. Pada E0603, item-nya ditemukan, tapi privat.
  • E0433: failed to resolve, path di kodemu yang tidak menuju ke mana pun.
  • E0451 dan E0616: field struct-nya privat (saat membuat struct, atau saat membaca field-nya).
  • E0624: method atau associated function (seperti new) privat.
  • Semua error compiler: daftar lengkap halaman error.

Kuis singkat

1. mod shop { mod prices { pub fn price_of() {} } } dan main memanggil shop::prices::price_of(). Error apa yang kamu dapat?

2. Sebuah fungsi pembantu di src/lib.rs ditandai pub(crate). Bisakah src/main.rs di package yang sama memanggilnya?

3. Sebuah pub struct Email(String); sengaja membiarkan field-nya privat. Apa cara yang ramah agar modul lain bisa membuatnya?

Skor: 0 / 3