Episode ini membangun program Rust pertama secara utuh: struktur crate binary dan library, tipe data dasar, variable immutability dan shadowing, fungsi dan expression, serta control flow dengan match dan if. Semua contoh bisa kalian jalankan langsung dengan cargo.

Setelah memahami arsitektur, saatnya menulis kode yang benar-benar terkompilasi. Episode 3 membangun sintaks dasar Rust: bagaimana program disusun, bagaimana variabel dan tipe bekerja, bagaimana fungsi ditulis sebagai expression, serta bagaimana control flow dan pattern matching mengambil keputusan.
Rust memiliki sintaks yang ekspresif namun disiplin. Kalian akan melihat perbedaan besar dari bahasa lain: variabel default immutable, fungsi berbasis expression, dan match yang ekshaustif. Semua contoh bisa kalian jalankan dengan cargo run di project yang dibuat di episode 0.
Binary crate dimulai dari src/main.rs dengan fungsi main. Cargo menjadikannya titik masuk program:
cat > src/main.rs <<'EOF'
fn main() {
let nama = "Rust";
println!("Halo, {}!", nama);
}
EOF
cargo runprintln!("Halo, {}!", nama) mencetak teks dengan placeholder. Binary crate sederhana ini cukup untuk mengeksplorasi hampir semua materi episode 3.
Untuk kode yang bisa diuji dan dipakai ulang, gunakan library crate: src/lib.rs mendeklarasikan fungsi publik yang dipanggil dari binary. Modul mengorganisir kode lebih lanjut:
cargo new --lib perpustakaan
mkdir perpustakaan/src/mathFile src/math/kuadrat.rs dipanggil dari lib.rs dengan deklarasi pub mod math. Modul membuat codebase besar tetap terstruktur — pola yang akan kalian pakai di project production.
Rust menyediakan tipe skalar: integer dengan lebar tetap seperti i32 dan u64, floating point f32 dan f64, boolean bool, serta karakter char. Tipe bisa disimpulkan otomatis oleh kompiler, tetapi tetap bisa dideklarasikan eksplisit.
cat > src/main.rs <<'EOF'
fn main() {
let umur: u32 = 25;
let harga = 19.99_f64;
let aktif = true;
let inisial = 'A';
println!("{} {} {} {}", umur, harga, aktif, inisial);
}
EOF
cargo runlet umur: u32 = 25 mendeklarasikan integer unsigned. Suffix 19.99_f64 menegaskan tipe literal. Sebagian besar waktu let cukup tanpa anotasi tipe karena kompiler menebaknya.
Variabel Rust immutable secara default: setelah diikat dengan let, nilainya tidak bisa diubah. Untuk nilai yang berubah, tambahkan mut. Shadowing memungkinkan mendeklarasikan ulang nama dengan let baru, mengubah tipe sekaligus:
cat > src/main.rs <<'EOF'
fn main() {
let nilai = 5;
let nilai = nilai + 2;
let nilai = nilai * 3;
println!("hasil: {}", nilai);
let teks = "angka";
let teks = teks.len();
println!("panjang: {}", teks);
}
EOF
cargo runShadowing membuat nilai baru dengan nama yang sama tanpa mengubah nilai lama. Ini berbeda dari mut yang mengubah nilai di tempat. Shadowing berguna untuk menurunkan nilai bertahap tanpa menambah nama variabel.
Fungsi Rust dideklarasikan dengan fn, parameter diberi tipe eksplisit, dan tipe kembalian ditulis setelah tanda panah:
cat > src/main.rs <<'EOF'
fn kuadrat(x: i32) -> i32 {
x * x
}
fn main() {
let hasil = kuadrat(7);
let bersyarat = if hasil > 10 { "besar" } else { "kecil" };
println!("{} {}", hasil, bersyarat);
}
EOF
cargo runPerhatikan x * x tanpa titik koma: itulah expression yang menjadi nilai kembalian. Di Rust, statement diakhiri titik koma sedangkan expression tidak. if juga merupakan expression yang menghasilkan nilai — pola idiomatis yang menggantikan ternary operator.
Aturan emasnya: tanpa titik koma berarti expression, dengan titik koma berarti statement. Pemahaman ini penting karena menentukan nilai yang dikembalikan fungsi. Compiler bahkan akan memperingatkan kalau let tidak menghasilkan apa pun.
cat > src/main.rs <<'EOF'
fn main() {
let mut counter = 0;
loop {
counter += 1;
if counter == 3 {
break;
}
}
for i in 0..3 {
println!("iterasi {}", i);
}
println!("counter: {}", counter);
}
EOF
cargo runloop berjalan tanpa henti sampai break, sedangkan for mengiterasi range 0..3. Range dengan tiga titik .. eksklusif: 0..3 mencakup 0, 1, dan 2. for adalah cara paling idiomatis mengiterasi koleksi.
match membandingkan nilai terhadap pola dan menjalankan cabang pertama yang cocok. Rust mewajibkan ekshaustif: semua kemungkinan harus ditangani, atau kompiler menolak program:
cat > src/main.rs <<'EOF'
fn label(status: u8) -> &'static str {
match status {
0 => "pending",
1 => "proses",
2 => "selesai",
_ => "tidak dikenal",
}
}
fn main() {
println!("{}", label(1));
}
EOF
cargo runPola _ menangkap semua nilai yang tidak cocok. match adalah alat utama Rust untuk mengambil keputusan berbasis nilai — kalian akan menggunakannya terus-menerus, terutama saat menangani Result dan Option di episode 4.
Inti yang harus dibawa pulang:
src/main.rs; library crate dari src/lib.rs.mut untuk mengubah, let baru untuk shadowing.if, loop, dan for adalah statement; if juga bisa menjadi expression.match harus ekshaustif dan menjadi fondasi pattern matching di Rust.Di episode 4 selanjutnya kita akan membahas error handling dan Result — tipe Result dan Option sebagai nilai error-safe, operator ? untuk propagasi error, serta custom error dengan thiserror dan anyhow. Inilah keterampilan yang paling sering dipakai di kode Rust production.