Cargo dan Crate di Rust
Di halaman Mulai dengan Rust, kamu sudah memakai cargo new dan cargo run. Itu baru permulaan. Cargo adalah build tool Rust sekaligus package manager-nya. Cargo meng-compile kodemu, menjalankan test, merapikan format file, dan mengunduh library yang ditulis orang lain.
Library-library itu disebut crate (paket kode Rust). Bayangkan crate seperti aplikasi di app store: orang lain sudah memecahkan sebuah masalah (membaca JSON, membuat web request, mem-parse tanggal), dan kamu bisa menambahkan solusi mereka ke proyekmu dengan satu perintah. Halaman ini menunjukkan cara kerjanya, dan cara memilih crate yang bagus.
Crate dan package
Section titled “Crate dan package”Ada dua istilah yang akan sering kamu dengar:
- Crate adalah satu unit kode Rust yang di-build oleh compiler. Crate bisa berupa binary (program yang bisa dijalankan, dimulai dari
src/main.rs) atau library (kode untuk dipakai program lain, dimulai darisrc/lib.rs). - Package adalah apa yang dibuat oleh
cargo new: sebuah folder berisi fileCargo.tomldan satu atau lebih crate di dalamnya.
Dalam percakapan sehari-hari, orang menyebut keduanya “crate”. Kalau seseorang bilang “pakai crate serde”, maksudnya “tambahkan package serde dari crates.io ke proyekmu”.
Isi Cargo.toml
Section titled “Isi Cargo.toml”Setiap package punya file Cargo.toml. File ini ditulis dalam format TOML (bahasa Inggris), format pengaturan yang sederhana. Inilah yang kamu dapat dari cargo new hello_rust:
[package]name = "hello_rust"version = "0.1.0"edition = "2024"
[dependencies][package]menjelaskan proyekmu.namedanversionadalah yang akan dilihat orang lain kalau kamu memublikasikannya.editionmemilih edisi bahasa Rust yang dipakai. Edisi (2018, 2021, 2024) memungkinkan Rust berkembang tanpa merusak kode lama. Biarkan saja apa pun yang ditulis olehcargo new.[dependencies]berisi daftar crate yang dipakai kodemu. Awalnya kosong.
Seiring proyek berkembang, kamu mungkin melihat bagian-bagian lain:
[dependencies]serde = { version = "1.0", features = ["derive"] }serde_json = "1.0"
[dev-dependencies]# hanya dipakai oleh test dan contoh, bukan oleh program aslimupretty_assertions = "1.4"
[profile.release]# pengaturan untuk `cargo build --release`opt-level = 3Menambahkan dependency dengan cargo add
Section titled “Menambahkan dependency dengan cargo add”Kamu bisa mengedit [dependencies] secara manual, tapi cara termudah adalah cargo add. Perintah ini mencari versi terbaru di crates.io dan menuliskan barisnya untukmu:
cargo add serde_jsonSebagian crate punya bagian opsional yang disebut features. Secara default, fitur-fitur ini dimatikan supaya hasil build tetap kecil. Kamu menyalakannya dengan --features:
cargo add serde --features deriveSetelah dua perintah ini, Cargo.toml kamu akan berisi kira-kira seperti ini:
[dependencies]serde = { version = "1.0.228", features = ["derive"] }serde_json = "1.0.145"Sekarang pakai crate itu di kodemu. cargo run berikutnya akan mengunduhnya, meng-compile-nya sekali, lalu menautkannya ke programmu:
use serde_json::json;
fn main() { let crab = json!({ "legs": 10, "name": "Ferris" });
println!("{}", crab); println!("Nama: {}", crab["name"]);}Output:
{"legs":10,"name":"Ferris"}Nama: "Ferris"Tanda kutip di sekitar "Ferris" muncul karena crab["name"] masih berupa nilai JSON, bukan string Rust biasa.
Rust Playground sudah menyertakan crate-crate paling populer, jadi kode ini bisa jalan di sana tanpa cargo add. Di komputermu sendiri, kamu perlu menjalankan cargo add serde_json terlebih dahulu. Kamu akan belajar jauh lebih banyak tentang crate ini di halaman JSON dengan Serde.
Untuk menghapus crate yang tidak kamu butuhkan lagi, jalankan cargo remove serde_json.
Aturan versi dan Cargo.lock
Section titled “Aturan versi dan Cargo.lock”Saat kamu menulis serde_json = "1.0", kamu tidak meminta tepat versi 1.0. Maksudmu adalah “versi apa pun yang kompatibel dengan 1.0”. Cargo mengikuti semantic versioning (SemVer): versi ditulis MAJOR.MINOR.PATCH, dan hanya perubahan pada angka major yang boleh merusak kodemu.
| Kamu menulis | Cargo boleh memakai | Alasannya |
|---|---|---|
"1.0" (sama dengan "^1.0") |
>=1.0.0 dan <2.0.0 |
semua versi 1.x seharusnya kompatibel |
"1.4.2" |
>=1.4.2 dan <2.0.0 |
minimal 1.4.2, tapi tetap 1.x |
"0.4" |
>=0.4.0 dan <0.5.0 |
sebelum 1.0, angka minor dianggap bisa merusak |
"~1.4" |
>=1.4.0 dan <1.5.0 |
hanya update patch |
"=1.4.2" |
tepat 1.4.2 |
jarang dibutuhkan |
Lalu siapa yang menentukan versi yang persis? Itulah tugas Cargo.lock. Saat pertama kali build, Cargo memilih versi terbaru yang cocok dengan aturanmu dan mencatatnya di Cargo.lock. Setiap build setelahnya memakai versi yang persis sama, di komputermu maupun di komputer orang lain.
- Jangan edit
Cargo.locksecara manual. Cargo yang mengurusnya. - Commit file ini ke git, terutama untuk program. Dengan begitu, rekan timmu dan CI kamu mem-build hal yang persis sama dengan yang kamu build.
cargo updateberpindah ke versi terbaru yang masih cocok denganCargo.toml, lalu menulis ulangCargo.lock. Perintah ini tidak pernah melompat ke versi major baru; untuk itu, kamu harus mengubahCargo.tomlsendiri.
Mencari crate yang bagus
Section titled “Mencari crate yang bagus”Ada tiga situs yang akan kamu pakai berulang kali (semuanya berbahasa Inggris):
- crates.io adalah registry resmi. Semua crate publik ada di sini. Cari dengan kata seperti “csv” atau “date”.
- docs.rs menampung dokumentasi setiap crate, yang dibuat secara otomatis. Contohnya, docs.rs/serde_json.
- lib.rs adalah indeks tidak resmi yang lebih cepat dan mengelompokkan crate berdasarkan kategori. Sangat cocok untuk melihat-lihat.
Banyak crate memecahkan masalah yang sama, jadi bagaimana cara memilihnya? Sebelum menambahkan sebuah crate, luangkan waktu sebentar untuk mengecek:
- Jumlah unduhan. Crate yang populer punya jutaan unduhan. Artinya, sudah banyak orang yang menemukan dan memperbaiki bug-nya sebelum kamu.
- Update terbaru. Lihat tanggal rilis terakhir. Crate yang tidak berubah selama bertahun-tahun mungkin masih baik-baik saja (ada yang memang sudah “selesai”), tapi pastikan repository-nya tidak penuh issue yang tidak dijawab.
- Dokumentasi. Buka halaman docs.rs-nya. Crate yang bagus punya halaman depan yang jelas dengan contoh yang bisa kamu salin.
- Versi 1.0 atau lebih. Tidak wajib, tapi ini menandakan penulisnya menjanjikan API yang stabil.
- Sedikit dependency. Setiap crate yang kamu tambahkan membawa dependency-nya sendiri. Makin kecil, makin mudah dipercaya.
Kalau ragu, cari “rust” ditambah masalahmu, lalu lihat crate mana yang terus-menerus direkomendasikan oleh komunitas.
Perintah Cargo yang penting
Section titled “Perintah Cargo yang penting”Kamu tidak perlu menghafal semuanya. Simpan tabel ini di dekatmu, dan kamu akan hafal sendiri dengan sering memakainya:
| Perintah | Fungsinya |
|---|---|
cargo new my_app |
Membuat proyek binary baru (tambahkan --lib untuk library) |
cargo build |
Meng-compile ke target/debug/ |
cargo run |
Meng-compile lalu menjalankan (argumen ditulis setelah --: cargo run -- input.txt) |
cargo check |
Mengecek error tanpa membuat program. Jauh lebih cepat daripada build |
cargo test |
Menjalankan test (lihat Testing di Rust) |
cargo fmt |
Merapikan format semua kodemu dengan gaya standar |
cargo clippy |
Menjalankan linter. Clippy menyarankan kode yang lebih sederhana dan lebih idiomatis |
cargo doc --open |
Membuat dokumentasi HTML untuk proyekmu dan semua dependency-nya, lalu membukanya |
cargo update |
Memperbarui Cargo.lock ke versi kompatibel terbaru |
cargo build --release |
Meng-compile program yang sudah dioptimalkan ke target/release/ |
Kebiasaan yang baik: sering jalankan cargo check selagi menulis kode, lalu cargo fmt dan cargo clippy sebelum commit. cargo doc --open juga permata tersembunyi. Perintah ini memberimu dokumentasi untuk versi crate yang persis kamu pakai, dan bisa dipakai offline.
Build debug vs release
Section titled “Build debug vs release”Secara default, Cargo membuat build debug. Build ini cepat di-compile dan menyimpan pemeriksaan keamanan tambahan, misalnya panic saat integer overflow. Itu sempurna selama kamu masih mengembangkan program.
Build release (cargo build --release atau cargo run --release) lebih lama di-compile, tapi berjalan jauh lebih cepat, sering kali 10 kali lipat atau lebih. Pakai build ini saat kamu merilis programmu atau mengukur kecepatannya.
Kodemu bahkan bisa tahu jenis build yang sedang dipakai:
fn main() { if cfg!(debug_assertions) { println!("Build debug: pemeriksaan tambahan aktif"); } else { println!("Build release: dioptimalkan untuk kecepatan"); }}Output:
Build debug: pemeriksaan tambahan aktifDi Playground, kamu bisa mengganti “Debug” menjadi “Release” lewat menu, lalu menjalankannya lagi untuk melihat baris yang lain.
Crate binary dan library sekaligus
Section titled “Crate binary dan library sekaligus”Sebuah package bisa berisi library dan binary sekaligus. Ini susunan yang sangat umum. Logika utamamu disimpan di src/lib.rs, sementara src/main.rs tetap kecil dan hanya memanggilnya:
greeter/├── Cargo.toml└── src/ ├── lib.rs # crate library: logika yang bisa dipakai ulang └── main.rs # crate binary: program yang kamu jalankanpub fn greet(name: &str) -> String { format!("Halo, {name}!")}fn main() { // nama library sama dengan nama package println!("{}", greeter::greet("Ferris"));}Kenapa dipisah seperti ini? Kode di lib.rs mudah di-test, dan program lain (atau binary kedua) bisa memakainya ulang. Playground hanya punya satu file, tapi kamu bisa merasakan hal yang sama dengan pub mod, seperti di halaman Modul di Rust:
mod greeter { pub fn greet(name: &str) -> String { format!("Halo, {name}!") }}
fn main() { println!("{}", greeter::greet("Ferris"));}Output:
Halo, Ferris!Sekilas tentang workspace
Section titled “Sekilas tentang workspace”Saat proyek berkembang menjadi beberapa package yang saling berkaitan (misalnya aplikasi command line, web server, dan library bersama), kamu bisa menaruhnya dalam satu workspace. Semuanya berbagi satu Cargo.lock dan satu folder target/, jadi semuanya di-build bersama dan memakai versi dependency yang sama.
Cargo.toml di tingkat paling atas berisi daftar anggotanya:
[workspace]members = ["app", "core"]resolver = "3"my_project/├── Cargo.toml # file workspace di atas├── Cargo.lock # dipakai bersama oleh semua anggota├── app/ # package binary└── core/ # package libraryLalu cargo build di tingkat atas akan mem-build semuanya, dan cargo run -p app menjalankan satu anggota. Kamu belum butuh ini untuk proyek-proyek pertamamu, tapi ada baiknya kamu mengenalinya saat membaca kode orang lain.
Kesalahan umum
Section titled “Kesalahan umum”Memakai crate tanpa menambahkannya. Kalau kamu menulis use serde_json::json; tapi lupa cargo add serde_json, compiler tidak bisa menemukannya:
error[E0432]: unresolved import `serde_json` --> src/main.rs:1:5 |1 | use serde_json::json; | ^^^^^^^^^^ use of unresolved module or unlinked crate `serde_json` | = help: you might be missing a crate named `serde_json`Compiler bilang import serde_json tidak ditemukan, dan mungkin kamu belum punya crate dengan nama itu. Solusinya, jalankan cargo add serde_json. Cek juga ejaannya: nama crate memakai - atau _, dan di dalam kode, - selalu berubah menjadi _.
Lupa menyalakan feature. Kalau #[derive(Serialize)] bilang tidak bisa menemukan derive macro, kemungkinan kamu menambahkan serde tanpa --features derive. Jalankan lagi cargo add serde --features derive; perintah ini akan memperbarui baris yang sudah ada.
Mengukur kecepatan dengan build debug. Kalau programmu terasa lambat, coba cargo run --release dulu sebelum mengubah kode apa pun.
Latihan
Section titled “Latihan”1. Pakai crate dari Playground
Section titled “1. Pakai crate dari Playground”Gunakan makro json! dari serde_json untuk mendeskripsikan sebuah crate dengan tiga key: downloads (angka), name, dan version. Cetak seluruh nilainya, lalu cetak versinya saja.
Petunjuk: tiru bentuk contoh crab di Menambahkan dependency dengan cargo add. Di komputermu sendiri, jalankan cargo add serde_json terlebih dahulu; Playground sudah memilikinya.
Lihat solusi
use serde_json::json;
fn main() { let krate = json!({ "downloads": 500, "name": "serde_json", "version": "1.0" });
println!("{}", krate); println!("Versi: {}", krate["version"]);}Output:
{"downloads":500,"name":"serde_json","version":"1.0"}Versi: "1.0"Variabelnya diberi nama krate karena crate adalah kata yang dicadangkan (reserved word) di Rust. Ejaan ini lelucon yang umum di kode Rust. Seperti sebelumnya, versinya dicetak dengan tanda kutip karena masih berupa nilai JSON; halaman JSON dengan Serde menunjukkan cara mengambil teks biasanya.
2. Pesan khusus build debug
Section titled “2. Pesan khusus build debug”Tulis fungsi debug_log(msg: &str) yang mencetak [debug] diikuti pesannya, tapi hanya di build debug. Pakai fungsi itu di main di sekitar perhitungan kecil, lalu cetak hasilnya seperti biasa.
Petunjuk: bungkus println! dengan if cfg!(debug_assertions) { ... }, seperti di Build debug vs release.
Lihat solusi
fn debug_log(msg: &str) { if cfg!(debug_assertions) { println!("[debug] {msg}"); }}
fn main() { debug_log("memulai perhitungan"); let mut total = 0; for n in 1..=10 { total += n; } debug_log("perhitungan selesai");
println!("Jumlah 1 sampai 10 adalah {total}");}Output:
[debug] memulai perhitungan[debug] perhitungan selesaiJumlah 1 sampai 10 adalah 55Ganti Playground ke “Release” (atau pakai cargo run --release di komputermu) lalu jalankan lagi: hanya baris terakhir yang tercetak. Untuk proyek sungguhan, halaman Logging di Rust menunjukkan crate yang menangani ini dengan benar, lengkap dengan level seperti debug dan info.
Ringkasan
Section titled “Ringkasan”- Cargo mem-build, menjalankan, menguji, dan merapikan format kodemu, serta mengunduh crate dari crates.io.
Cargo.tomlberisi apa yang kamu minta;Cargo.lockmencatat versi persis yang kamu dapat. Commit keduanya.cargo add nama --features xmenambahkan dependency."1.0"berarti “versi 1.x apa pun yang kompatibel”.- Nilai sebuah crate dari jumlah unduhan, update terbaru, dan dokumentasi yang bagus di docs.rs.
- Pakai
cargo checkselagi menulis kode,cargo fmtdancargo clippysebelum commit, dan--releaseuntuk kecepatan. - Taruh logika yang bisa dipakai ulang di
src/lib.rs, dan biarkansrc/main.rstetap kecil.
Kuis singkat
Section titled “Kuis singkat”Kuis singkat
1. Di Cargo.toml, apa arti serde_json = "1.0"?
2. File mana yang mencatat versi persis dari setiap dependency yang dipakai build-mu?
3. Kamu ingin mengecek error di kodemu secepat mungkin, tanpa menghasilkan program. Perintah mana yang paling cocok?
4. Bagaimana cara menambahkan serde dengan feature derive yang menyala?
Skor: 0 / 4
Bacaan lebih lanjut
Section titled “Bacaan lebih lanjut”- The Cargo Book (bahasa Inggris): panduan dan referensi resmi untuk semua yang bisa dilakukan Cargo.
- Specifying Dependencies — The Cargo Book (bahasa Inggris): semua cara menulis aturan versi, ditambah dependency dari git dan path lokal.
cargo add— The Cargo Book (bahasa Inggris): semua opsicargo add, seperti--dev,--features, dan--no-default-features.- More about Cargo and Crates.io — The Rust Book (bahasa Inggris): release profile, memublikasikan crate milikmu sendiri, dan memasang tool dengan
cargo install. - Cargo Workspaces — The Rust Book (bahasa Inggris): contoh workspace langkah demi langkah dengan satu binary dan dua library.