Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Mendefinisikan Modul untuk Mengontrol Scope dan Privasi

Di bagian ini, kita bakal bahas modul dan bagian lain dari sistem modul, yaitu paths (jalur), yang ngebolehin kita buat namain item; keyword use yang bawa sebuah path ke dalem scope; dan keyword pub buat bikin item jadi public. Kita juga bakal bahas keyword as, external packages (package eksternal), dan operator glob.

Contekan (Cheat Sheet) Modul

Sebelum kita masuk ke detail soal modul dan paths, di sini kita nyediain referensi cepet soal gimana cara kerja modul, paths, keyword use, sama keyword pub di compiler, dan gimana kebanyakan developer ngatur kode mereka. Kita bakal ngebahas contoh-contoh dari tiap aturan ini di sepanjang bab ini, tapi tempat ini cocok sekali buat dijadiin pengingat soal gimana modul itu jalan.

  • Mulai dari crate root: Pas nge-compile sebuah crate, compiler pertama kali nyari di file crate root (biasanya src/lib.rs buat library crate atau src/main.rs buat binary crate) buat nyari kode yang mau di-compile.
  • Mendeklarasikan modul: Di file crate root, kita bisa mendeklarasikan modul baru; katakanlah kita mendeklarasikan modul “garden” pake mod garden;. Compiler bakal nyari kode modul itu di tempat-tempat ini:
    • Inline, di dalem kurung kurawal yang nggantiin titik koma setelah mod garden
    • Di file src/garden.rs
    • Di file src/garden/mod.rs
  • Mendeklarasikan submodul: Di file mana pun selain crate root, kita bisa mendeklarasikan submodul. Misalnya, kita mungkin mendeklarasikan mod vegetables; di src/garden.rs. Compiler bakal nyari kode submodul itu di dalem direktori yang namanya sama kayak modul induk (parent)-nya di tempat-tempat ini:
    • Inline, langsung setelah mod vegetables, di dalem kurung kurawal bukannya titik koma
    • Di file src/garden/vegetables.rs
    • Di file src/garden/vegetables/mod.rs
  • Paths ke kode di modul: Begitu sebuah modul jadi bagian dari crate kita, kita bisa ngerujuk ke kode di modul itu dari mana pun di crate yang sama, selama aturan privasinya ngebolehin, pake path ke kodenya. Misalnya, tipe Asparagus di modul vegetables dari garden bakal ditemuin di crate::garden::vegetables::Asparagus.
  • Private vs. public: Kode di dalem sebuah modul itu private (privat) dari modul induknya secara default. Buat bikin modul jadi public (publik), deklarasikan pake pub mod bukannya mod. Buat bikin item di dalem modul public ikutan jadi public juga, pake pub sebelum deklarasinya.
  • Keyword use: Di dalem sebuah scope, keyword use bikin shortcut (jalan pintas) ke item buat ngurangin pengulangan paths yang panjang. Di scope mana pun yang bisa ngerujuk ke crate::garden::vegetables::Asparagus, kita bisa bikin shortcut pake use crate::garden::vegetables::Asparagus; dan dari situ kita cuma perlu nulis Asparagus buat pake tipe itu di scope tersebut.

Di sini, kita bikin sebuah binary crate namanya backyard yang nunjukin aturan-aturan ini. Direktori crate-nya, yang juga namanya backyard, punya file dan direktori ini:

backyard
├── Cargo.lock
├── Cargo.toml
└── src
    ├── garden
    │   └── vegetables.rs
    ├── garden.rs
    └── main.rs

File crate root di kasus ini adalah src/main.rs, dan isinya:

Filename: src/main.rs
use crate::garden::vegetables::Asparagus;

pub mod garden;

fn main() {
    let plant = Asparagus {};
    println!("I'm growing {plant:?}!");
}

Baris pub mod garden; ngasih tau compiler buat masukin kode yang dia nemu di src/garden.rs, yaitu:

Filename: src/garden.rs
pub mod vegetables;

Di sini, pub mod vegetables; artinya kode di src/garden/vegetables.rs juga dimasukin. Kode itu adalah:

#[derive(Debug)]
pub struct Asparagus {}

Sekarang yuk kita masuk ke detail dari aturan-aturan ini dan demonstrasikan pas lagi dipake!

Ngelempokin Kode yang Terkait di Modul

Modul ngebolehin kita ngatur kode di dalem sebuah crate buat readability (keterbacaan) dan biar gampang dipake ulang (reuse). Modul juga ngebolehin kita ngontrol privasi dari item karena kode di dalem sebuah modul itu private secara default. Item private adalah detail implementasi internal yang nggak tersedia buat dipake dari luar. Kita bisa milih buat bikin modul dan item di dalemnya jadi public, yang nge-ekspos mereka biar kode eksternal bisa pake dan bergantung pada mereka.

Sebagai contoh, yuk kita tulis sebuah library crate yang nyediain fungsionalitas dari sebuah restoran. Kita bakal mendefinisikan signature dari fungsi-fungsinya tapi ngebiarin body-nya kosong buat fokus ke organisasi kodenya bukannya implementasi dari restorannya.

Di industri restoran, beberapa bagian dari restoran disebut front of house (bagian depan) dan yang lainnya back of house (bagian dapur). Front of house itu tempat para pelanggan berada; ini nyakup tempat para host ngarahin pelanggan ke tempat duduk, pelayan nerima pesanan dan pembayaran, dan bartender bikin minuman. Back of house itu tempat para koki dan tukang masak kerja di dapur, pencuci piring bersih-bersih, dan manajer ngelakuin kerjaan administratif.

Buat menstruktur crate kita pake cara ini, kita bisa ngatur fungsi-fungsinya ke dalem modul yang bersarang. Bikin library baru namanya restaurant dengan jalanin cargo new restaurant --lib. Terus masukin kode di Listing 7-1 ke src/lib.rs buat mendefinisikan beberapa modul dan signature fungsi; kode ini adalah bagian front of house.

Filename: src/lib.rs
mod front_of_house {
    mod hosting {
        fn add_to_waitlist() {}

        fn seat_at_table() {}
    }

    mod serving {
        fn take_order() {}

        fn serve_order() {}

        fn take_payment() {}
    }
}
Listing 7-1: Sebuah modul front_of_house yang nyimpen modul lain yang terus nyimpen fungsi

Kita mendefinisikan sebuah modul pake keyword mod diikuti sama nama modulnya (di kasus ini, front_of_house). Body dari modulnya ditaruh di dalem kurung kurawal. Di dalem modul, kita bisa naruh modul lain, kayak di kasus ini pake modul hosting sama serving. Modul juga bisa nampung definisi buat item lain, kayak struct, enum, konstanta, trait, dan kayak di Listing 7-1, fungsi.

Dengan pake modul, kita bisa ngelempokin definisi yang terkait dan ngasih nama kenapa mereka terkait. Programmer yang pake kode ini bisa navigasi kodenya berdasarkan kelompok-kelompoknya bukannya harus baca semua definisinya satu-satu, bikin lebih gampang buat nemuin definisi yang relevan buat mereka. Programmer yang nambahin fungsionalitas baru ke kode ini bakal tau ke mana harus naruh kodenya biar programnya tetep teratur.

Tadi, kita sempet nyebut kalau src/main.rs sama src/lib.rs itu disebut crate roots. Alasan dinamain gitu karena isi dari salah satu dari dua file ini ngebentuk modul namanya crate di root dari struktur modul crate itu, yang dikenal sebagai module tree (pohon modul).

Listing 7-2 nunjukin pohon modul buat struktur di Listing 7-1.

crate
 └── front_of_house
     ├── hosting
     │   ├── add_to_waitlist
     │   └── seat_at_table
     └── serving
         ├── take_order
         ├── serve_order
         └── take_payment
Listing 7-2: Pohon modul buat kode di Listing 7-1

Pohon ini nunjukin gimana beberapa modul bersarang di dalem modul lain; misalnya, hosting bersarang di dalem front_of_house. Pohonnya juga nunjukin kalau beberapa modul itu saling sodaraan (siblings), artinya mereka didefinisikan di modul yang sama; hosting sama serving itu sodaraan yang didefinisikan di dalem front_of_house. Kalau modul A ada di dalem modul B, kita bilang kalau modul A itu anaknya (child) modul B dan modul B itu induknya (parent) modul A. Perhatiin ya kalau seluruh pohon modul itu berakar di bawah modul implisit yang namanya crate.

Pohon modul mungkin ngingetin kita sama pohon direktori sistem file di komputer kita; ini perbandingan yang pas sekali! Kayak direktori di sistem file, kita pake modul buat ngatur kode kita. Dan kayak file di dalem direktori, kita perlu cara buat nemuin modul kita.