Tipe integer menyimpan nilai dalam jumlah bit yang tetap, seperti u8 yang hanya punya delapan bit untuk angka 0 s.d. 255. Batas ini biasanya tidak terasa, sampai suatu ketika counter lampu di angka 255 ditambah satu, atau suhu -128 derajat dikurangi satu lagi. Kejadian tersebut bernama integer overflow: hasil perhitungan keluar dari jangkauan tipe sehingga representasi binernya tidak lagi muat. Insiden teknik nyata berakar pada masalah sederhana ini, mulai dari roket Ariane 5 yang menghancurkan dirinya sendiri karena angka navigasi tidak muat saat dikonversi ke integer sempit, hingga YouTube yang terpaksa memperluas penghitung tayangannya setelah satu video melampaui batas bilangan 32-bit. Rust mengambil pendekatan yang berbeda per mode kompilasi: mode debug menghentikan program saat overflow terjadi, sementara mode release membiarkan nilai berputar. Pada Chapter ini kita akan membuktikan kedua perilaku itu secara nyata, lalu mempelajari metode checked, wrapping, saturating, dan overflowing untuk mengendalikan overflow secara eksplisit.
Mode Debug: Program Berhenti dengan panic #
Kompilasi tanpa optimasi apa pun adalah mode debug, dan mode ini memasang pemeriksaan overflow pada setiap operasi aritmetika integer. Ketika hasil perhitungan melampaui jangkauan tipe, program berhenti total melalui mekanisme panic. Kode berikut menambah nilai u8 yang sudah berada di batas maksimum:
fn main() {
let mut lampu: u8 = 255;
lampu = lampu + 1;
println!("Nilai lampu: {}", lampu);
}Simpan kode tersebut sebagai main.rs, lalu kompilasi dan jalankan tanpa optimasi:
rustc --edition 2021 main.rs -o program_debug
./program_debugProgram tidak pernah mencetak apa pun; ia berhenti dengan keluaran berikut:
thread 'main' (6823) panicked at main.rs:4:13:
attempt to add with overflow
note: run with `RUST_BACKTRACE=1` environment variable to display a backtraceMari kita bedah kejadiannya:
- Baris 2 (
let mut lampu: u8 = 255;): variablelampumenyimpan255, nilai terbesar yang mampu ditampung delapan bit tanpa bertanda. - Baris 4 (
lampu = lampu + 1;): pemeriksaan debug mendeteksi hasil256melebihi jangkauanu8sebelum nilai disimpan; program langsung panic di titik ini dan baris setelahnya tidak pernah tereksekusi. - Lokasi
main.rs:4:13: pasangan angka menunjuk baris dan kolom operasi penjumlahan; angka dalam tanda kurung setelah katamainadalah nomor thread sistem operasi yang berbeda pada setiap eksekusi.
Pesan attempt to add with overflow menyebut operasi yang gagal secara spesifik, sehingga kita langsung tahu harus memeriksa penjumlahan mana. Perilaku menghentikan program tampak keras, tetapi inilah tujuannya: data korup yang berjalan diam-diam jauh lebih mahal daripada program yang berhenti dengan pesan jelas.
Mode Release: Nilai Berputar dengan Wrapping #
Saat mengompilasi dengan optimasi (-O atau cargo build --release), pemeriksaan overflow dilepas demi kecepatan eksekusi, dan operasi integer mengikuti perilaku wrapping dua komplemen (two’s complement): bit yang meluber terbuang dan nilai melanjutkan dari ujung rentang yang lain. Kita buktikan dengan mengompilasi ulang berkas yang sama:
rustc --edition 2021 -O main.rs -o program_release
./program_releaseOutput yang Dihasilkan:
Nilai lampu: 0Mari kita amati prosesnya bit demi bit:
- Nilai 255 dalam biner delapan bit adalah
11111111. - Penambahan 1 menghasilkan
100000000dengan sembilan bit, sementarau8hanya menyimpan delapan bit. - Bit kesembilan terbuang, menyisakan
00000000yang dibaca sebagai0; nilai berputar dari batas atas ke batas bawah seolah mengitari jam.
Untuk tipe bertanda seperti i8, putaran terjadi pada dua ujungnya: batas bawah -128 dikurangi satu menghasilkan 127, karena pola bit 10000000 bergeser menjadi 01111111. Jika kita memakai Cargo dalam proyek nyata, cargo run memakai mode debug, sedangkan cargo run --release memakai mode release; beda perilaku inilah alasan mengapa bug overflow kerap baru muncul di lingkungan produksi.
Metode checked: Menolak Hasil yang Meluap #
Metode checked_add, checked_sub, dan checked_mul mengembalikan hasil pembungkus: Some(hasil) ketika perhitungan aman, atau None ketika terjadi overflow. Dengan bentuk hasil tersebut, kode kita dipaksa menghadapi kedua kemungkinan secara eksplisit:
fn main() {
let lampu: u8 = 255;
match lampu.checked_add(1) {
Some(hasil) => println!("255 + 1 = {}", hasil),
None => println!("255 + 1 overflow, penjumlahan dibatalkan"),
}
match lampu.checked_sub(10) {
Some(hasil) => println!("255 - 10 = {}", hasil),
None => println!("255 - 10 overflow, pengurangan dibatalkan"),
}
}Output yang Dihasilkan:
255 + 1 overflow, penjumlahan dibatalkan
255 - 10 = 245Mari kita bedah mekanismenya:
- Baris 4 (
lampu.checked_add(1)): karena255 + 1melampaui 255, method mengembalikanNone; cabangNonepadamatchyang terpilih dan penjumlahan dibatalkan tanpa panic. - Baris 9 (
lampu.checked_sub(10)):255 - 10 = 245masih di dalam jangkauan, sehingga method mengembalikanSome(245)dan cabang pertama mencetak hasilnya.
Metode wrapping dan saturating #
Ketika nilai berputar justru diinginkan, metode wrapping_ menyatakannya secara eksplisit dan berperilaku sama di semua mode kompilasi. Sebaliknya, metode saturating_ menahan nilai di batas terdekat alih-alih berputar: penjumlahan yang melampaui maksimum berhenti tepat di maksimum:
fn main() {
let lampu: u8 = 255;
let titik_beku: i8 = -128;
println!("u8 255 wrapping_add(1) : {}", lampu.wrapping_add(1));
println!("i8 -128 wrapping_sub(1) : {}", titik_beku.wrapping_sub(1));
println!("u8 255 saturating_add(1): {}", lampu.saturating_add(1));
println!("i8 -128 saturating_sub(1): {}", titik_beku.saturating_sub(1));
}Output yang Dihasilkan:
u8 255 wrapping_add(1) : 0
i8 -128 wrapping_sub(1) : 127
u8 255 saturating_add(1): 255
i8 -128 saturating_sub(1): -128Mari kita bedah keempat hasilnya:
- Baris 5 (
lampu.wrapping_add(1)):255 + 1berputar ke0, sama seperti perilaku mode release, tetapi kini dinyatakan gamblang di dalam kode. - Baris 6 (
titik_beku.wrapping_sub(1)):-128 - 1berputar ke batas atasi8, yaitu127, sesuai hukum dua komplemen. - Baris 7 (
lampu.saturating_add(1)): nilai menepi di255alih-alih berputar; saturating cocok untuk data seperti persentase atau volume yang tidak boleh melompat ke nol. - Baris 8 (
titik_beku.saturating_sub(1)): padai8bawah,saturating_submenahan nilai di-128karena sudah berada di batas minimum.
Pilihan antara keduanya adalah keputusan domain: counter jam berputar masuk akal, sedangkan stok barang atau skor kelayakan kredit harus memakai saturating agar tidak tiba-tiba nol.
Metode overflowing: Hasil Sekaligus Tanda Meluap #
Metode overflowing_ mengembalikan tuple berisi hasil perhitungan dan penanda boolean apakah overflow terjadi. Bentuk ini menghubungkan langsung materi tuple pada Chapter Tipe Data Komposit:
fn main() {
let lampu: u8 = 255;
let (hasil, meluap) = lampu.overflowing_add(1);
println!("255 + 1 = {}, meluap: {}", hasil, meluap);
let (hasil_aman, meluap_aman) = lampu.overflowing_add(0);
println!("255 + 0 = {}, meluap: {}", hasil_aman, meluap_aman);
}Output yang Dihasilkan:
255 + 1 = 0, meluap: true
255 + 0 = 255, meluap: falseMari kita telaah bentuk keluarannya:
- Baris 4 (
let (hasil, meluap) = lampu.overflowing_add(1);): destructuring tuple memisahkan dua anggota;hasilberisi0karena wrapping terjadi, danmeluapbernilaitrue. - Baris 7 (
lampu.overflowing_add(0)): penjumlahan dengan nol tidak pernah meluap, sehingga tuple berisi255danfalse.
Metode ini pas ketika kita butuh hasil wrapping sekaligus catatan diagnostik, misalnya mencatat kejadian overflow ke log tanpa menghentikan program.
Ringkasan #
Integer overflow terjadi ketika hasil perhitungan keluar dari jangkauan tipe. Mode debug menghentikan program dengan panic attempt to add with overflow lengkap dengan lokasi baris, sedangkan mode release membiarkan nilai berputar mengikuti dua komplemen. Metode checked_ mengembalikan Some/None agar overflow ditangani eksplisit, wrapping_ menyatakan putaran secara sah lintas mode, saturating_ menahan nilai di batas terdekat, dan overflowing_ mengembalikan hasil beserta tanda meluap dalam satu tuple. Pemilihan metode yang tepat bergantung pada makna data: putaran untuk siklus, saturasi untuk batas, dan checked untuk penolakan. Section Dasar Sintaks telah lengkap; selanjutnya kita masuk ke Kontrol Alur untuk mengatur jalur eksekusi program.