Semua contoh kita sejauh ini menumpuk module di satu berkas — dan itu memang pilihan wajar untuk program kecil. Namun begitu satu module menampung ratusan baris, berkas tunggal menjadi beban: editor lambat dibuka, konflik merge bertambah, dan penulis kode saling menginjak file yang sama. Rust mengizinkan setiap module pindah ke berkas sendiri tanpa mengubah satu pun aturan yang sudah kita pelajari — tree module, path, hingga visibility tetap bekerja identik. Perpindahan ditandai lewat satu perubahan kecil pada deklarasi mod: blok isi dihapus, titik koma ditambahkan, dan kompilator mencari isi module di berkas lain. Chapter ini memandu pemindahan tersebut pada proyek cargo sungguhan.
mod Tanpa Isi Merujuk Berkas #
Dua bentuk deklarasi module perlu kita bedakan tuntas. Bentuk pertama sudah kita kenal: mod utils { ... } dengan blok isi langsung — disebut module inline. Bentuk kedua memotong blok dan menggantinya dengan titik koma: mod utils;. Titik koma itu adalah instruksi bagi kompilator untuk mencari isi module utils pada berkas src/utils.rs atau src/utils/mod.rs — relatif terhadap lokasi berkas yang mendeklarasikan. Isi berkas tersebut kemudian diperlakukan persis seperti isi blok {}: tree module hasil akhirnya tidak berbeda sedikit pun dari versi inline, sehingga path crate::utils::... dan aturan pub tetap sama.
Konsekuensi pentingnya satu arah: deklarasi mod tetap harus ada pada module induk. Compiler tidak memindai seluruh folder src/ untuk menebak module — hanya deklarasi mod utils; yang mengikat sebuah berkas ke tree. Berkas .rs yang tidak pernah dideklarasikan hanya menjadi berkas biasa yang tidak ikut dikompilasi.
Kedua bentuk juga boleh berdampingan dalam satu crate — bahkan dalam satu module induk. Sebuah mod config; yang merujuk berkas dapat hidup di sebelah mod helper { ... } yang tetap inline, dan masing-masing berperilaku sama di tree. Pemilihan bentuk biasanya mengikuti ukuran: module kecil berisi satu-dua fungsi penolong lebih enak dibaca inline di dekat induknya, sedangkan module besar pindah ke berkas sendiri. Karena bentuk tidak memengaruhi path maupun visibility, perpindahan dari inline ke berkas terpisah — atau sebaliknya — tidak mengubah satu pun baris pemanggilan di tempat lain.
Proyek Contoh: restoran dengan Module Terpisah #
Kita bangun proyek cargo resto_pesan yang memindahkan seluruh module ke berkas masing-masing. Struktur akhirnya sebagai berikut:
resto_pesan/
├── Cargo.toml
└── src/
├── main.rs
├── utils.rs
├── front_of_house.rs
└── front_of_house/
└── hosting.rsEmpat berkas itu memuat pembagian kerja berikut. Berkas crate root src/main.rs hanya mendeklarasikan module dan menjalankan alur utama:
mod utils;
mod front_of_house;
fn main() {
utils::sambut_pelanggan("Budi");
front_of_house::buka_pintu();
front_of_house::hosting::add_to_waitlist();
}Berkas src/utils.rs menjadi isi module utils:
pub fn sambut_pelanggan(nama: &str) {
println!("Selamat datang, {}!", nama);
}Berkas src/front_of_house.rs menjadi isi module front_of_house, sekaligus mendeklarasikan anaknya:
pub mod hosting;
pub fn buka_pintu() {
println!("Pintu depan restoran dibuka");
}Berkas src/front_of_house/hosting.rs menjadi isi module hosting yang bersarang:
pub fn add_to_waitlist() {
println!("Pelanggan masuk daftar tunggu");
}Jalankan proyek dengan perintah biasa:
cargo runOutput yang Dihasilkan:
Selamat datang, Budi!
Pintu depan restoran dibuka
Pelanggan masuk daftar tungguMari kita bedah berkas-berkas tersebut:
- Baris 1 pada main.rs (
mod utils;): deklarasi module tanpa blok. Kompilator membaca titik koma sebagai perintah mencarisrc/utils.rs— ditemukan, lalu seluruh isi berkas itu menjadi isi moduleutils. - Baris 3 pada main.rs (
mod front_of_house;): pola yang sama menautkansrc/front_of_house.rske tree sebagai anak crate root. - Baris 6–8 pada main.rs: pemanggilan memakai path seperti biasa. Dari sudut pandang
main, tidak ada bedanya module tinggal di berkas lain — pathutils::sambut_pelanggan(...)danfront_of_house::hosting::add_to_waitlist()sama persis dengan versi inline pada Chapter sebelumnya. - Baris 1 pada front_of_house.rs (
pub mod hosting;): deklarasi bersarang tetap ditulis di berkas induk, namun karena berkas ini sendiri bernamafront_of_house.rs, kompilator mencari anak pada foldersrc/front_of_house/hosting.rs. Aturan pencariannya mengikuti jalur folder: deklarasimod X;di dalam berkasY.rsdicari padaY/X.rsatauY/X/mod.rsdi folder yang sama. - Baris 3–5 pada front_of_house.rs (
pub fn buka_pintu()): modulefront_of_housetetap boleh memiliki item sendiri di samping deklarasi anak — berkas bukan sekadar daftarmod.
Pola folder ini memungkinkan kedalaman tree berapapun: module hosting bisa punya cucu src/front_of_house/hosting/pesan.rs dengan deklarasi mod pesan; di dalam hosting.rs, dan seterusnya mengikuti nama folder.
Berkas yang Terlupakan: E0583 #
Jebakan paling sering pada pola ini adalah lupa membuat berkas setelah menulis deklarasi. Tambahkan mod dapur; di baris pertama src/main.rs tanpa membuat berkasnya, lalu jalankan cargo build:
error[E0583]: file not found for module `dapur`
--> src/main.rs:1:1
|
1 | mod dapur;
| ^^^^^^^^^^
|
= help: to create the module `dapur`, create file "src/dapur.rs" or "src/dapur/mod.rs"
= note: if there is a `mod dapur` elsewhere in the crate already, import it with `use crate::...` instead
For more information about this error, try `rustc --explain E0583`.
error: could not compile `resto_pesan` (bin "resto_pesan") due to 1 previous errorError E0583 bermuatan bantuan yang lengkap: dua lokasi berkas yang diterima kompilator dituliskan jelas, lengkap dengan catatan untuk kasus module yang memang sudah dideklarasikan di tempat lain. Baliknya juga terjadi — berkas src/dapur.rs yang ada tanpa deklarasi mod dapur; tidak menghasilkan error, tetapi berkas itu diam-diam tidak pernah ikut dikompilasi, dan pemanggilan dapur::... akan gagal E0432 karena module itu tidak terdaftar di tree. Aturan praktisnya: satu module, satu deklarasi, satu berkas.
Dua Gaya Penempatan: file.rs versus mod.rs #
Rust menerima dua konvensi penempatan berkas anak: gaya modern menaruh deklarasi induk di front_of_house.rs dengan anak pada folder front_of_house/hosting.rs, sedangkan gaya lama menaruh segalanya di dalam folder — induk menjadi front_of_house/mod.rs dan anak tetap front_of_house/hosting.rs. Keduanya sah sepenuhnya dan boleh dicampur dalam satu crate, meski mencampurnya membuat struktur sulit diprediksi.
Komunitas modern condong ke gaya front_of_house.rs. Alasannya praktis: sebuah folder yang memuat banyak anak akan memunculkan banyak mod.rs di editor sekaligus — tab bernama sama, tab yang mudah tertukar — sementara gaya modern menghasilkan nama berkas yang unik dan mencerminkan module-nya. Gaya modern juga menjadikan daftar isi folder src/ terbaca sebagai daftar module tingkat atas.
Ringkasan #
Deklarasi mod utils; dengan titik koma memindahkan isi module ke berkas src/utils.rs (atau src/utils/mod.rs); deklarasi tetap ditulis pada module induk sehingga tree, path, dan visibility tidak berubah. Module bersarang mengikuti struktur folder — induk front_of_house.rs mendeklarasikan anak yang dicari di front_of_house/hosting.rs — dan kedalaman berapa pun berlanjut dengan pola yang sama. Kebiasaan lupa berkas dijawab E0583 beserta saran lokasinya, sementara pilihan gaya file.rs versus mod.rs boleh mengikuti selera tim dengan catatan konsisten. Struktur berkas sehat sudah kita miliki; Chapter berikutnya menaikkannya ke level proyek dengan memisahkan library dan binary lewat src/lib.rs.