Program yang menghitung total belanja, mengelola stok gudang, atau melacak saldo pengguna bekerja dengan pola yang sama: menyimpan sebuah nilai ke dalam nama yang mudah diingat, lalu membaca kembali nilai tersebut saat dibutuhkan. Rust menyediakan mekanisme variable untuk keperluan tersebut, tetapi dengan satu keputusan desain yang mengejutkan bagi kita yang datang dari PHP atau JavaScript: secara bawaan, variable di Rust bersifat immutable atau tidak dapat diubah setelah diberi nilai. Pada Chapter ini kita akan membuat variable dengan kata kunci let, mengalami langsung galat kompilasi ketika mencoba mengubah variable immutable, lalu memperbaikinya dengan kata kunci mut. Pada akhir chapter kita juga akan memahami alasan Rust memilih keamanan sebagai jalur bawaan.
Mengikat Nilai dengan let #
Variable di Rust adalah pengenal (identifier) yang mengikat sebuah nama ke sebuah nilai. Kata kunci let memberi tahu kompilator untuk menyiapkan tempat bagi nilai tersebut, menentukan tipenya, dan mendaftarkan nama variable di dalam scope saat ini. Berbeda dengan PHP, penulisan nama variable di Rust tidak diawali tanda $, dan setiap statement wajib diakhiri titik koma.
Kita mulai dari contoh paling sederhana, yaitu menghitung total belanja:
fn main() {
let harga = 50000;
let jumlah = 3;
let total = harga * jumlah;
println!("Harga satuan: Rp{}", harga);
println!("Jumlah: {}", jumlah);
println!("Total: Rp{}", total);
}Output yang Dihasilkan:
Harga satuan: Rp50000
Jumlah: 3
Total: Rp150000Mari kita telaah apa yang terjadi pada baris-baris kode di atas:
- Baris 2 (
let harga = 50000;): kata kunciletmembuat variable bernamahargadan mengikatnya ke nilai integer50000; kompilator menentukan tipehargasebagaii32, yaitu tipe bawaan untuk bilangan bulat. - Baris 3 (
let jumlah = 3;): variablejumlahdibuat dengan nilai3menggunakan pola yang sama. - Baris 4 (
let total = harga * jumlah;): kompilator membaca nilai darihargadanjumlah, mengalikan keduanya menjadi150000, lalu mengikat hasilnya ke variable baru bernamatotal. - Baris 6-8 (
println!(...)): ketiga baris mencetak nilai setiap variable ke terminal; tanda kurung kurawal{}berfungsi sebagai slot yang diganti oleh nilai variable di belakang tanda koma.
Perhatikan bahwa program di atas membaca harga dua kali, yaitu pada baris 4 dan baris 6. Membaca nilai berulang kali tidak masalah, karena yang dilarang bukan membaca, melainkan menimpa nilai tanpa izin.
Variable Rust Bersifat Immutable secara Bawaan #
Masalah nyata muncul ketika data memang perlu berubah, misalnya stok gudang berkurang setiap kali barang terjual. Insting kita mungkin menulis stok = stok - 4; seperti pola di PHP. Mari kita coba langsung dan lihat reaksi kompilator:
fn main() {
let stok = 10;
println!("Stok awal: {}", stok);
stok = stok - 4;
println!("Stok akhir: {}", stok);
}Kode tersebut gagal dikompilasi. Pesan galat lengkapnya berbunyi:
error[E0384]: cannot assign twice to immutable variable `stok`
--> main.rs:5:5
|
2 | let stok = 10;
| ---- first assignment to `stok`
...
5 | stok = stok - 4;
| ^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
|
help: consider making this binding mutable
|
2 | let mut stok = 10;
| +++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0384`.Galat E0384 menyebutkan dua lokasi sekaligus: baris ke-2 tempat stok pertama kali diberi nilai, dan baris ke-5 tempat kita mencoba memberi nilai kedua. Kompilator bahkan memberikan saran perbaikan berupa penambahan kata kunci mut pada deklarasi awal. Perlu kita garis bawahi bahwa galat ini terjadi sebelum program sempat berjalan; Rust menolak menghasilkan program biner dari kode yang melanggar aturan mutabilitas.
Membuat Variable Mutable dengan mut #
Ketika sebuah nilai memang dirancang berubah, kita menyatakannya secara eksplisit dengan menambahkan kata kunci mut di antara let dan nama variable. Kata kunci ini berlaku sejak deklarasi, bukan ditambahkan di tengah program. Berikut perbaikan dari kode sebelumnya:
fn main() {
let mut stok = 10;
println!("Stok awal: {}", stok);
stok = stok - 4;
println!("Stok akhir: {}", stok);
}Output yang Dihasilkan:
Stok awal: 10
Stok akhir: 6Mari kita bedah perubahan pentingnya:
- Baris 2 (
let mut stok = 10;): kata kuncimutmemberi izin kepada variablestokuntuk diberi nilai baru di kemudian hari; nilai awalnya tetap10. - Baris 5 (
stok = stok - 4;): baris ini sekarang sah; kompilator membaca nilai lamastokyaitu10, menguranginya dengan4, lalu menimpa isistokdengan hasil6. - Baris 6 (
println!("Stok akhir: {}", stok);): pencetakan menunjukkan isistokyang terbaru, sehingga tercetak6.
Kata kunci mut hanya mengizinkan penimpaan nilai dengan tipe yang sama. Kita boleh menulis stok = 8; karena 8 juga bilangan bulat, tetapi menulis stok = 8.5; akan ditolak karena tipe berubah menjadi bilangan desimal. Teknik mengubah nilai sekaligus tipenya akan kita pelajari pada Chapter Shadowing Variabel.
Sebagai bukti, program berikut memberi nilai awal lalu hanya membaca stok tanpa pernah menimpanya:
fn main() {
let mut stok = 10;
println!("Stok: {}", stok);
}Program tetap berjalan dan mencetak Stok: 10, tetapi kompilator menampilkan peringatan berikut:
warning: variable does not need to be mutable
--> main.rs:2:9
|
2 | let mut stok = 10;
| ----^^^^
| |
| help: remove this `mut`
|
= note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default
warning: 1 warning emittedMengapa Rust Memilih Keamanan #
Sebagian besar kesalahan pemrograman yang sulit dilacak berasal dari data yang berubah tanpa disadari. Sebuah variable yang diubah di tempat jauh dari tempat pembacaannya memaksa kita menelusuri kode secara manual hanya untuk mengetahui nilai terkini. Dengan immutable sebagai bawaan, kompilator menjamin bahwa variable yang kita baca masih memegang nilai yang sama sejak dideklarasikan, kecuali deklarasinya secara eksplisit mengandung mut.
Keputusan ini juga berbuah pada program yang menjalankan banyak thread. Thread lain yang membaca variable immutable tidak perlu khawatir nilainya diganti di tengah jalan, sehingga banyak kelas galat concurrency berkurang bahkan sebelum program berjalan. Terakhir, penandaan mut membuat niat kode terbaca jelas: setiap kemunculan mut adalah titik yang layak kita periksa saat melakukan code review atas logika bisnis.
Ringkasan #
Kata kunci let mengikat nama ke nilai, dan variable seperti itu bersifat immutable secara bawaan. Upaya menimpa variable immutable digagalkan kompilator lewat galat E0384, lengkap dengan saran penambahan mut. Kata kunci mut dinyatakan saat deklarasi dan hanya mengizinkan penimpaan nilai bertipe sama. Dengan fondasi ini, kita siap mengenal tipe-tipe data yang dapat disimpan ke dalam variable pada Chapter Tipe Data Skalair.