1. Variabel & Mutability (Kekekalan)
Ini adalah konsep pertama yang wajib kamu pahami. Di kebanyakan bahasa (Python, JS, C++), variabel itu bebas diubah isinya.
Di Rust? Tidak. Secara default, semua variabel adalah Immutable (Kekal/Tidak bisa diubah).
Mengapa begitu?
Rust sangat peduli pada keamanan memori dan concurrency (jalan barengan). Jika data tidak bisa berubah, maka data itu aman dibaca oleh banyak thread sekaligus tanpa takut "balapan" (race condition).
Contoh Kode:
fn main() {
let x = 5;
println!("Nilai x adalah: {}", x);
// x = 6; // ❌ ERROR! Ini akan gagal di-compile.
// Karena x secara default tidak bisa diubah.
}
Solusi: Gunakan mut
Jika kamu butuh variabel yang bisa berubah (misal untuk counter), tambahkan kata kunci mut (mutable).
fn main() {
let mut y = 10; // ✅ Ada 'mut', jadi boleh berubah
println!("Nilai y awal: {}", y);
y = 20;
println!("Nilai y sekarang: {}", y);
}
Aturan Emas: Selalu gunakan
letbiasa. Hanya gunakanlet mutjika kamu benar-benar yakin nilainya perlu berubah.
2. Tipe Data (Data Types)
Rust adalah bahasa statically typed (tipe data harus jelas saat compile). Tapi, Rust cukup pintar untuk menebak tipe data (type inference), jadi kamu tidak harus selalu menulisnya.
Ada dua kategori besar tipe data primitif:
A. Scalar Types (Nilai Tunggal)
- Integer (Bilangan Bulat):
i32(Default): Bilangan bulat (bisa negatif). Paling sering dipakai.u32: Unsigned (hanya positif).i64/u64: Untuk angka yang sangat besar.
- Floating Point (Desimal):
f64(Default): Presisi ganda, lebih akurat.f32: Presisi tunggal.
- Boolean:
trueataufalse.
- Character (
char):
- Menggunakan tanda kutip satu
'a'. - Di Rust,
charitu 4 bytes (Unicode), jadi bisa nyimpen Emoji! 😻
let age: i32 = 25;
let rating: f64 = 4.5;
let is_active: bool = true;
let icon: char = '🦀'; // Valid di Rust!
B. Compound Types (Kumpulan Data)
- Tuple: Kumpulan nilai dengan tipe data yang bisa berbeda. Panjangnya tetap.
- Array: Kumpulan nilai dengan tipe data yang harus sama. Panjangnya tetap.
// Tuple
let tup: (i32, f64, u8) = (500, 6.4, 1);
let (x, y, z) = tup; // Destructuring (membongkar tuple)
// Array (disimpan di Stack, bukan Heap)
let months = ["Jan", "Feb", "Mar"];
let first = months[0];
3. Fungsi (Functions)
Fungsi di Rust dideklarasikan dengan kata kunci fn. Konvensi penamaannya menggunakan snake_case (huruf kecil semua dengan garis bawah).
Struktur dasar fungsi:
fn main() {
hello_world();
hitung_luas(10, 5);
}
// Fungsi sederhana
fn hello_world() {
println!("Halo dari fungsi!");
}
// Fungsi dengan parameter
fn hitung_luas(panjang: i32, lebar: i32) {
println!("Luasnya adalah: {}", panjang * lebar);
}
💡 The "Return Value" Magic (Penting!)
Di Rust, kita jarang pakai kata kunci return di akhir fungsi.
- Statement: Instruksi yang melakukan sesuatu tapi tidak mengembalikan nilai. (Diakhiri titik koma
;) - Expression: Menghasilkan nilai. (TIDAK diakhiri titik koma).
Lihat bedanya:
// Fungsi yang mengembalikan nilai integer (i32)
fn tambah_lima(angka: i32) -> i32 {
let hasil = angka + 5;
hasil // 👈 Perhatikan! TIDAK ADA titik koma (;)
// Ini artinya "return hasil"
}
// Kalau kamu tulis "hasil;" (pakai titik koma), itu jadi statement,
// dan fungsi akan error karena tidak mengembalikan apa-apa.
4. Komentar & Printing
Komentar
Sama seperti C/Java/JS:
// Ini komentar satu baris
/* Ini komentar
banyak baris
*/
Printing (Macro)
Kamu akan sering melihat println!.
Tanda seru ! menandakan itu adalah Macro, bukan fungsi biasa (kita bahas bedanya nanti).
let nama = "Budi";
let skor = 90;
// Gunakan {} sebagai placeholder
println!("Halo {}, skor kamu {}", nama, skor);
Tentu, ini pertanyaan yang sangat bagus dan krusial! Banyak pemula bingung di sini karena di bahasa lain (seperti Python atau Java), print itu fungsi biasa.
Mari kita bedah kenapa Rust butuh Macro (!) untuk mencetak teks.
🔍 Bedah println!: Kenapa Pakai Tanda Seru?
Secara sederhana, Macro adalah fitur di Rust yang memungkinkan kita menulis kode yang menulis kode lain (metaprogramming).
Bayangkan perbedaannya seperti ini:
- Fungsi (
fn): Seperti Aktor. Dia bekerja saat panggung dibuka (saat program berjalan/runtime). Tugasnya spesifik dan kaku. - Macro (
!): Seperti Penulis Naskah. Dia bekerja sebelum panggung dibuka (saat kompilasi). Dia bisa mengubah naskah, menambah dialog, atau menyusun ulang adegan sebelum aktor masuk.
Kenapa println! harus jadi macro (Penulis naskah)? Ada 2 alasan utama:
1. Jumlah Argumen yang Berubah-ubah (Variadic)
Di Rust, sebuah Fungsi biasa memiliki aturan yang sangat ketat: Jumlah parameternya harus pas.
Jika kamu punya fungsi tambah(a, b), kamu HARUS memasukkan 2 angka. Tidak boleh 1, tidak boleh 3.
Tapi coba lihat println!:
println!("Halo!"); // 0 argumen tambahan
println!("Halo {}", nama); // 1 argumen tambahan
println!("Halo {}, umur {}", nama, umur); // 2 argumen tambahan
println! bisa menerima jumlah input yang bebas!
Rust tidak mendukung fungsi dengan jumlah parameter bebas (seperti *args di Python) secara default demi keamanan memori. Makanya, Rust menggunakan Macro untuk mengakalinya.
2. Pengecekan Error Sebelum Program Jalan
Ini adalah fitur "sakti" Rust. Coba lihat kode ini:
let x = 10;
println!("Nilai x adalah: {} dan y adalah: {}", x);
// ❌ Error! Kita minta 2 tempat ({}), tapi cuma kasih 1 variabel (x).
Jika println adalah fungsi biasa, error ini mungkin baru ketahuan saat program sedang berjalan (runtime error), yang bisa bikin aplikasi crash tiba-tiba.
Tapi karena println! adalah Macro:
- Saat kamu tekan tombol "Run", Macro akan "membaca" kodemu dulu.
- Dia menghitung jumlah kurung kurawal
{}. - Dia menghitung jumlah variabel yang kamu masukkan.
- Jika tidak cocok, dia menolak untuk membuat programnya (Compile Error).
- Programmu dijamin aman dari error print bahkan sebelum dijalankan.
🧠 Visualisasi: Apa yang Terjadi di Belakang Layar?
Saat kamu menulis kode singkat ini:
println!("Halo {}", "Dunia");
Sebelum menjadi aplikasi jadi (.exe), Macro akan "mengembangkan" (expand) kode itu menjadi baris-baris kode asli yang rumit dan panjang untuk menangani input/output (I/O) standar.
Kalau kamu harus menulis kode I/O itu secara manual setiap kali mau nge-print, tanganmu bakal keriting! Macro melakukannya untukmu secara otomatis.
⚔️ Ringkasan: Fungsi vs Macro
| Fitur | Fungsi Biasa (fn) |
Macro (!) |
|---|---|---|
| Kapan Diproses? | Saat program jalan (Runtime) | Saat program dikompilasi (Compile Time) |
| Jumlah Argumen | Harus tetap (Fixed) | Bisa berubah-ubah (Flexible) |
| Bentuk | nama_fungsi() |
nama_macro!() |
| Contoh | tambah(), main() |
println!, vec!, panic! |
Kesimpulan:
Tanda seru ! itu adalah sinyal bagi programmer: "Hei, ini bukan pemanggilan fungsi biasa. Ada sihir (kode otomatis) yang terjadi di sini sebelum program dijalankan!"
🎯 Tantangan Mini (Latihan)
Coba buat file baru latihan.rs atau ubah main.rs kamu. Tulis kode untuk:
- Buat variabel mutable
suhudengan nilai 30. - Cetak nilainya.
- Ubah
suhujadi 35. - Buat fungsi
konversi_fahrenheityang menerimasuhu(Celcius) dan mengembalikan nilai Fahrenheit. (Rumus:(C * 9/5) + 32). - Cetak hasil konversinya.
Selamat mencoba! Kalau error, baca pesan error-nya pelan-pelan. Compiler Rust itu guru terbaikmu. 😉