Menulis semua kebutuhan program dari nol adalah pilihan yang mahal: pengacakan angka butuh algoritma teruji, format tanggal butuh penanganan kalender, dan serialisasi data butuh ratusan detail. Ekosistem Rust menjawabnya dengan crates.io — registry publik yang menampung puluhan ribu crate siap pakai yang dipublikasikan komunitas. Cargo terintegrasi penuh dengan registry tersebut: satu perintah cargo add cukup untuk mengunduh, mengompilasi, dan menautkan library eksternal ke proyek kita. Pada Chapter ini kita menambahkan crate rand ke proyek undian, mengamati seluruh proses di balik layar mulai dari unduhan sampai terbentuknya berkas kunci versi, lalu memakai library tersebut dalam kode sungguhan.

Registry crates.io dan Peran Cargo #

crates.io berperan sebagai registry: server tempat crate dipublikasikan, dicari, dan diunduh. Setiap crate di registry punya nama unik, nomor versi, dan daftar versi rilisnya. Registry juga menyimpan index — kumpulan metadata ringkas berisi nama, versi, dan dependency tiap crate — yang bisa diperiksa cargo dengan cepat tanpa mengunduh isi crate sepenuhnya.

Cargo memakai registry ini lewat dua jalur: jalur metadata saat menyelesaikan versi mana yang dipasang, dan jalur unduhan saat mengambil berkas sumber crate. Kedua jalur tersebut otomatis dijalankan oleh cargo build — kita tidak pernah mengunduh dan mengekstrak berkas secara manual seperti pada beberapa bahasa lain. Semua berkas yang pernah diunduh tersimpan di cache ~/.cargo/registry, sehingga proyek lain yang memakai crate sama tidak mengunduh ulang.

Cache tersebut terbagi dua subfolder dengan tugas berbeda: ~/.cargo/registry/cache menampung arsip .crate terkompresi persis seperti yang diunggah penulisnya, sedangkan ~/.cargo/registry/src menampung hasil ekstraksinya yang dipakai rustc saat kompilasi. Pemisahan ini menjelaskan mengapa menghapus satu subfolder tidak merusak yang lain — cargo cukup mengekstrak ulang dari arsip tanpa menyentuh jaringan.

Menambahkan Dependency dengan cargo add #

Proyek kita bernama undian-acak: sebuah program yang memilih satu pemenang dari daftar peserta. Kebutuhan pengacakan tidak perlu kita tulis sendiri — crate rand adalah standar de facto di ekosistem Rust. Masuk ke folder proyek, lalu jalankan:

bash
cargo add rand

Output yang Dihasilkan:

text
    Updating crates.io index
      Adding rand v0.10.3 to dependencies
             Features:
             + alloc
             + std
             + std_rng
             + sys_rng
             + thread_rng
             - chacha
             - log
             - serde
             - simd_support
             - unbiased
    Updating crates.io index
     Locking 8 packages to highest Rust 1.99.0 compatible versions

Perintah sekecil itu melakukan tiga hal. Pertama, cargo menyegarkan salinan index crates.io — baris Updating crates.io index. Kedua, cargo menuliskan baris rand = "0.10.3" ke tabel [dependencies] di Cargo.toml, dengan versi terbaru yang ditemukannya. Ketiga, cargo menyelesaikan dependency dan menampilkan daftar features milik rand — tanda + berarti aktif secara bawaan, tanda - berarti nonaktif; daftar ini pemanasan untuk Chapter Fitur Features. Baris Locking 8 packages memberi tahu bahwa rand membawa serta tujuh crate pendukung, dan seluruh rangkaian itu dicatat versi pastinya ke Cargo.lock.

Manifest proyek kini memuat satu baris dependency:

toml
[package]
name = "undian-acak"
version = "0.1.0"
edition = "2024"

[dependencies]
rand = "0.10.3"

Apa yang Terjadi Saat cargo build Pertama #

Dengan dependency tercatat di manifest, cargo build menjalankan rangkaian proses yang lebih panjang dari biasanya:

bash
cargo build

Output yang Dihasilkan:

text
 Downloading crates ...
  Downloaded cfg-if v1.0.5
  Downloaded rand_core v0.10.1
  Downloaded cpufeatures v0.3.1
  Downloaded getrandom v0.4.3
  Downloaded chacha20 v0.10.2
  Downloaded rand v0.10.3
  Downloaded libc v0.2.190
   Compiling libc v0.2.190
   Compiling cfg-if v1.0.5
   Compiling getrandom v0.4.3
   Compiling rand_core v0.10.1
   Compiling cpufeatures v0.3.1
   Compiling chacha20 v0.10.2
   Compiling rand v0.10.3
   Compiling undian-acak v0.1.0 (/tmp/w5a/undian-acak)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1.94s

Alur di balik layar berjalan berurutan. Cargo membaca tabel [dependencies], memeriksa Cargo.lock — berkas baru yang barusan dibuat — untuk mengetahui versi pasti tiap crate, mengunduh berkas sumber ke cache ~/.cargo/registry, lalu mengompilasi dependency satu per satu mulai dari yang paling dasar: libc dan cfg-if dikerjakan lebih dulu karena tidak bergantung pada apa pun, rand_core menyusul, hingga akhirnya rand sendiri, baru kemudian kode kita. Cargo juga menjalankan kompilasi dependency yang saling bebas secara paralel — jumlah proses rustc yang hidup bersamaan mengikuti banyaknya inti prosesor — sehingga proyek dengan puluhan dependency tetap selesai dalam waktu wajar. Unduhan hanya terjadi sekali — cargo build kedua tanpa perubahan hanya melaporkan Finished ... in 0.01s karena semua crate di cache dan hasil kompilasi masih valid.

Berkas Cargo.lock yang tercipta merekam resolusi versi:

text
[[package]]
name = "rand"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af"

Setiap entri menyimpan versi pasti, sumber registry, dan checksum untuk memastikan berkas yang diunduh tidak berubah. Nilai rand = "0.10.3" di manifest sebenarnya adalah requirement — rentang versi yang diterima — sedangkan Cargo.lock yang menyimpan versi final yang terpasang. Perbedaan keduanya menjadi pokok bahasan Chapter Versi dan SemVer.

Perilaku berkas lock paling terasa pada kondisi nyata: rekan tim yang meng-clone repositori kita mendapatkan Cargo.lock yang sama, sehingga cargo build di komputernya memakai rand 0.10.3 dan keenam pendukungnya dengan versi identik tanpa satu pun keputusan ulang. Registry tetap disentuh hanya untuk mengunduh berkas yang belum ada di cache — versi sudah diputuskan sejak awal.

Menggunakan rand dalam Program #

Kode sumber src/main.rs memakai rand untuk memilih pemenang:

rust
use rand::{rng, RngExt};

fn main() {
    let peserta = ["Budi", "Siti", "Rina", "Agus", "Dewi"];
    let indeks = rng().random_range(0..peserta.len());
    let pemenang = peserta[indeks];
    println!("Pemenang undian bulan ini: {}", pemenang);
    println!("Kupon keberuntungan: {}", rng().random_range(1000..9999));
}

Jalankan program beberapa kali:

bash
cargo run
cargo run
cargo run

Output yang Dihasilkan:

text
Pemenang undian bulan ini: Rina
Kupon keberuntungan: 4313
text
Pemenang undian bulan ini: Dewi
Kupon keberuntungan: 9343
text
Pemenang undian bulan ini: Budi
Kupon keberuntungan: 1050

Mari kita bedah kode di atas:

  1. Baris 1 (use rand::{rng, RngExt};): mengimpor dua item dari crate rand — fungsi rng yang membuat generator angka acak dari sumber sistem operasi, dan trait RngExt pemilik metode random_range. Trait harus dibawa ke scope agar metodenya bisa dipanggil, sesuai aturan yang sudah kita kenal di Section Traits.
  2. Baris 4 (let peserta = ["Budi", "Siti", "Rina", "Agus", "Dewi"];): array lima peserta sebagai data undian.
  3. Baris 5 (let indeks = rng().random_range(0..peserta.len());): rng() membuat generator, lalu random_range mengambil satu angka dari rentang 0..5. Rentang eksklusif ujung membuat hasil maksimal 4 — selalu menjadi indeks sah array.
  4. Baris 6 (let pemenang = peserta[indeks];): mengambil nama pemenang dari array lewat indeks acak tersebut.
  5. Baris 8 (println!("Kupon keberuntungan: {}", rng().random_range(1000..9999));): generator kedua mengambil nomor kupon empat digit; rentang 1000..9999 tidak pernah menghasilkan angka di bawah seribu.

Tiga kali menjalankan menghasilkan tiga hasil berbeda — perilaku persis yang kita cari dari library pengacakan.

Menghapus Dependency #

Kebalikan cargo add tersedia untuk membersihkan manifest — misalnya ketika library ternyata tidak terpakai:

bash
cargo remove rand

Output yang Dihasilkan:

text
    Removing rand from dependencies

Perintah tersebut menghapus baris rand = "0.10.3" dari tabel [dependencies]; kode yang masih mengimpor rand akan gagal dikompilasi dengan E0432 sampai baris use ikut dibersihkan. Crate yang terlanjur terunduh tetap tinggal di cache ~/.cargo/registry — cache bersifat arsip, bukan daftar aktif proyek, sehingga tidak memengaruhi build mana pun.

Ringkasan #

cargo add rand menuliskan requirement versi ke manifest, mengunduh crate beserta dependency pendukungnya dari crates.io ke cache lokal, mengompilasi berurutan dari paling dasar, dan merekam hasil resolusi ke Cargo.lock. Kode kita tinggal mengimpor item publik crate lewat use — fungsi rng dan metode random_range milik trait RngExt menghasilkan angka acak yang berubah di tiap eksekusi. Requirement "0.10.3" yang ditulis cargo add bukan versi terpasang yang kaku, melainkan rentang; cara membaca rentang itulah pembahasan Chapter berikutnya.