Aplikasi kasir menjumlahkan harga, mengalikan dengan jumlah, memotong diskon, lalu membandingkan total dengan batas minimal transaksi. Seluruh kegiatan itu digerakkan dua keluarga operator: aritmetika untuk menghitung dan perbandingan untuk menguji hubungan antar nilai. Keduanya terlihat sama dengan PHP, tetapi Rust membawa satu aturan ketat yang mengubah cara kita menulis: kedua operan harus bertipe persis sama, tanpa konversi otomatis sekecil apa pun. Pada Chapter ini kita akan menghitung dengan lima operator aritmetika, membedah perilaku pembagian integer, memakai operator perbandingan, dan mengalami langsung galat saat tipe operan berbeda.

Operator Aritmetika #

Rust menyediakan lima operator aritmetika dasar yang bekerja pada tipe integer dan floating point:

OperatorOperasiContoh
+penjumlahansubtotal + ongkir
-pengurangantotal - diskon
*perkalianharga * jumlah
/pembagiantotal / 2
%sisa bagi (modulus)total % 7

Kita langsung praktik menghitung struk belanja:

rust
fn main() {
    let harga_satuan = 15_000;
    let jumlah = 4;
    let ongkir = 25_000;

    let subtotal = harga_satuan * jumlah;
    let total = subtotal + ongkir;
    let setelah_diskon = total - 5_000;
    let bagi_rata = setelah_diskon / 2;
    let sisa = setelah_diskon % 7;

    println!("Subtotal: Rp{}", subtotal);
    println!("Total: Rp{}", total);
    println!("Setelah diskon: Rp{}", setelah_diskon);
    println!("Bagi rata: Rp{}", bagi_rata);
    println!("Sisa bagi: {}", sisa);
}

Output yang Dihasilkan:

text
Subtotal: Rp60000
Total: Rp85000
Setelah diskon: Rp80000
Bagi rata: Rp40000
Sisa bagi: 4

Mari kita bedah perhitungan pada tiap barisnya:

  1. Baris 6 (let subtotal = harga_satuan * jumlah;): operator * mengalikan 15000 dengan 4 menghasilkan 60000.
  2. Baris 7 (let total = subtotal + ongkir;): operator + menjumlahkan 60000 dengan ongkir 25000 menjadi 85000.
  3. Baris 8 (let setelah_diskon = total - 5_000;): operator - memotong 5000 dari total sehingga tersisa 80000.
  4. Baris 9 (let bagi_rata = setelah_diskon / 2;): operator / membagi 80000 dengan 2 menjadi 40000.
  5. Baris 10 (let sisa = setelah_diskon % 7;): operator % mencari sisa 80000 dibagi 7; karena 7 x 11428 = 79996, sisanya adalah 4.

Seluruh operan bertipe i32, sehingga setiap hasil juga i32 dan perhitungan berjalan mulus. Aturan tipe inilah yang menjadi fokus kita di bagian akhir chapter.

Pembagian Integer Memotong Angka Desimal #

Pembagian dua integer di Rust menghasilkan integer, dan bagian desimalnya dipotong lurus ke arah nol (truncation), bukan dibulatkan ke atas atau ke terdekat. Perilaku ini sering mengejutkan pemula yang mengharapkan hasil 2.85 dari 20 / 7. Kita buktikan dengan membagikan apel kepada anak-anak:

rust
fn main() {
    let jumlah_apel = 20;
    let jumlah_anak = 7;

    let apel_per_anak = jumlah_apel / jumlah_anak;
    let apel_sisa = jumlah_apel % jumlah_anak;

    println!("{} apel untuk {} anak", jumlah_apel, jumlah_anak);
    println!("Setiap anak mendapat {} apel", apel_per_anak);
    println!("Sisa {} apel untuk ibu", apel_sisa);

    let pembagian_float = 20.0 / 7.0;
    println!("Hasil pembagian float: {}", pembagian_float);
}

Output yang Dihasilkan:

text
20 apel untuk 7 anak
Setiap anak mendapat 2 apel
Sisa 6 apel untuk ibu
Hasil pembagian float: 2.857142857142857

Mari kita amati tiga hasil berbeda di atas:

  1. Baris 5 (let apel_per_anak = jumlah_apel / jumlah_anak;): 20 / 7 secara matematis bernilai 2.857..., tetapi karena kedua operan bertipe integer, hasilnya dipotong menjadi 2.
  2. Baris 6 (let apel_sisa = jumlah_apel % jumlah_anak;): operator % melengkapi pembagian dengan sisa 6; pola hasil x pembagi + sisa = angka asli berlaku, yaitu 2 x 7 + 6 = 20.
  3. Baris 12 (let pembagian_float = 20.0 / 7.0;): penulisan 20.0 dan 7.0 membuat kedua operan bertipe floating point, sehingga hasilnya mempertahankan angka desimal 2.857142857142857.

Kombinasi / dan % pada integer adalah pola standar untuk membagikan barang secara adil, sedangkan pembagian desimal menuntut kedua operan ditulis sebagai floating point.

Operator Perbandingan #

Enam operator perbandingan menguji hubungan dua nilai dan selalu menghasilkan bool:

OperatorMaknaContoh hasil
==sama dengan25000 == 25000 menjadi true
!=tidak sama dengan20000 != 25000 menjadi true
<lebih kecil20000 < 25000 menjadi true
>lebih besar25000 > 20000 menjadi true
<=lebih kecil atau sama20000 <= 20000 menjadi true
>=lebih besar atau sama20000 >= 25000 menjadi false

Kita bandingkan harga dua minuman di kedai:

rust
fn main() {
    let harga_kopi = 25_000;
    let harga_teh = 20_000;

    println!("Kopi > teh : {}", harga_kopi > harga_teh);
    println!("Kopi = teh : {}", harga_kopi == harga_teh);
    println!("Teh < kopi : {}", harga_teh < harga_kopi);
    println!("Teh <= kopi: {}", harga_teh <= harga_kopi);
    println!("Teh != kopi: {}", harga_teh != harga_kopi);
}

Output yang Dihasilkan:

text
Kopi > teh : true
Kopi = teh : false
Teh < kopi : true
Teh <= kopi: true
Teh != kopi: true

Setiap ekspresi seperti harga_kopi > harga_teh dievaluasi menjadi true atau false, lalu nilai boolean itu dicetak langsung oleh println!. Nilai hasil perbandingan juga bisa disimpan ke variable bertipe bool dan dipakai sebagai kondisi if, yang akan kita manfaatkan di section Kontrol Alur.

Kedua Operan Harus Bertipe Sama #

Aturan paling khas Rust adalah larangan pencampuran tipe pada operasi aritmetika. PHP secara diam-diam mengonversi "5" + 3.5 menjadi 8.5; Rust menolak keras karena konversi senyap adalah sumber bug presisi yang sulit dilacak. Kode berikut mengalikan bilangan bulat dengan bilangan desimal:

rust
fn main() {
    let harga = 25_000;
    let diskon = 0.1;

    let harga_setelah_diskon = harga - harga * diskon;
    println!("Harga setelah diskon: Rp{}", harga_setelah_diskon);
}

Kompilasi gagal dengan inti pesan berikut:

text
error[E0277]: cannot multiply `{integer}` by `{float}`
 --> main.rs:5:46
  |
5 |     let harga_setelah_diskon = harga - harga * diskon;
  |                                              ^ no implementation for `{integer} * {float}`
  |
  = help: the trait `Mul<{float}>` is not implemented for `{integer}`

error: aborting due to 1 previous error

Rust kemudian menampilkan daftar panjang kombinasi tipe yang sah untuk perkalian, tetapi pesan intinya sudah jelas: operator * tidak memiliki implementasi untuk integer dikali float. Solusinya ada dua, dan keduanya membuat konversi terlihat telanjang di kode. Pertama, samakan tipe sejak awal dengan menulis let harga = 25_000.0; dan let diskon = 0.1; sehingga semuanya floating point. Kedua, konversikan eksplisit di titik perhitungan, misalnya harga as f64 * diskon, yang akan kita kuasai pada Chapter Konversi Tipe dengan as.

Ringkasan #

Lima operator aritmetika (+, -, *, /, %) bekerja pada integer dan floating point, dengan hasil pembagian integer yang dipotong ke arah nol dan sisa bagi yang tersedia lewat %. Enam operator perbandingan menghasilkan bool dan menjadi bahan baku kondisi. Batasan utama yang harus kita patuhi: kedua operan wajib bertipe persis sama karena Rust tidak melakukan konversi otomatis antar tipe. Selanjutnya kita melanjutkan ke operator logika dan bitwise yang mengoperasikan nilai kebenaran dan bit-bit data.