Sistem sering mengambil keputusan berlapis: pesanan boleh diproses jika pembayaran lunas dan alamat terverifikasi; lampu menyala jika salah satu sensor mendeteksi gerakan. Keputusan berlapis seperti itu diekspresikan dengan operator logika &&, ||, dan !. Di sisi lain, sebagian domain bekerja pada aras yang lebih dalam, misalnya hak akses berkas dan pengolahan data sensor yang diwakili bit demi bit; untuk itu Rust menyediakan operator bitwise &, |, ^, <<, dan >>. Kedua keluarga operator ini memakai simbol yang mirip sehingga pemula sering tertukar, padahal mekanisme kerjanya sangat berbeda. Pada Chapter ini kita akan memakai keduanya dan membuktikan perbedaannya lewat perilaku short-circuit.
Operator Logika #
Tiga operator logika bekerja pada nilai bool dan menghasilkan bool baru:
| Operator | Nama | Hasil true ketika |
|---|---|---|
&& | AND logika | kedua operan true |
|| | OR logika | salah satu operan true |
! | NOT (pembalik) | operan bernilai false |
Kita uji ketiganya pada syarat masuk kelas:
fn main() {
let sudah_daftar = true;
let sudah_bayar = false;
println!("Boleh masuk kelas: {}", sudah_daftar && sudah_bayar);
println!("Punya akses terbatas: {}", sudah_daftar || sudah_bayar);
println!("Belum daftar: {}", !sudah_daftar);
}Output yang Dihasilkan:
Boleh masuk kelas: false
Punya akses terbatas: true
Belum daftar: falseMari kita bedah hasil tiap barisnya:
- Baris 5 (
sudah_daftar && sudah_bayar): operator&&menuntut kedua syarat terpenuhi; karenasudah_bayarbernilaifalse, hasilnyafalse. - Baris 6 (
sudah_daftar || sudah_bayar): operator||cukup dengan satu syarat;sudah_daftaryang bernilaitruemembuat hasilnyatrue. - Baris 7 (
!sudah_daftar): operator!membalik nilai, sehinggatruemenjadifalse.
Operator logika adalah bahan utama kondisi if, dan sebelum kita sampai ke sana, ada satu perilakunya yang wajib dipahami lebih dalam.
Short-Circuit Evaluation #
Operator && dan || milik Rust mengevaluasi operan kiri terlebih dahulu, lalu memutuskan apakah operan kanan masih perlu diperiksa. Jika operan kiri && sudah false, hasil pasti false dan operan kanan tidak dievaluasi sama sekali; sebaliknya jika operan kiri || sudah true, hasil pasti true dan operan kanan dilewati. Perilaku ini bernama short-circuit evaluation, dan justru karena sifat inilah kode pelindung bisa ditulis aman:
fn main() {
let pembagi = 0;
let nilai = 100;
if pembagi != 0 && nilai / pembagi > 10 {
println!("Hasil pembagian lebih besar dari 10");
} else {
println!("Pembagian tidak dilakukan");
}
}Output yang Dihasilkan:
Pembagian tidak dilakukanMari kita amati urutan kejadian di dalam kondisi:
- Baris 5 (
if pembagi != 0 && nilai / pembagi > 10): operan kiripembagi != 0dievaluasi lebih dulu dan menghasilkanfalsekarenapembagimemang0. - Sisi kanan (
nilai / pembagi > 10): ruas ini tidak pernah dievaluasi; short-circuit pada&&menyelamatkan program dari pembagian nol yang berujung panic. - Blok
else: karena kondisi utama bernilaifalse, blokelseyang dieksekusi dan mencetak pesan aman.
Operator Bitwise #
Operator bitwise memproses representasi biner dari integer, bit demi bit, dan hanya berlaku pada tipe bilangan bulat:
| Operator | Nama | Perilaku per bit |
|---|---|---|
& | AND | hasil 1 jika kedua bit 1 |
| | OR | hasil 1 jika salah satu bit 1 |
^ | XOR | hasil 1 jika kedua bit berbeda |
! | NOT | membalik setiap bit |
<< | geser kiri | menggeser bit ke kiri |
>> | geser kanan | menggeser bit ke kanan |
Penggunaan klasiknya adalah mask izin: satu bilangan menyimpan banyak tanda izin, satu bit mewakili satu izin. Kita siapkan izin baca (0100 = 4) dan izin tulis (0010 = 2), lalu gabungkan keduanya dengan OR:
fn main() {
let izin_baca: u8 = 0b0100;
let izin_tulis: u8 = 0b0010;
let izin_gabungan = izin_baca | izin_tulis;
println!("Izin baca: {:b}", izin_baca);
println!("Izin tulis: {:b}", izin_tulis);
println!("Gabungan: {:b} ({})", izin_gabungan, izin_gabungan);
println!("Punya izin baca: {}", (izin_gabungan & izin_baca) != 0);
println!("Punya izin hapus: {}", (izin_gabungan & 0b1000) != 0);
}Output yang Dihasilkan:
Izin baca: 100
Izin tulis: 10
Gabungan: 110 (6)
Punya izin baca: true
Punya izin hapus: falseMari kita bedah operasi bit pada tiap barisnya:
- Baris 5 (
let izin_gabungan = izin_baca | izin_tulis;): operator|menyatukan kedua mask menjadi0b0110alias6; bit ke-2 menyala dari izin baca dan bit ke-1 menyala dari izin tulis. - Baris 7-9 (
println!("...", {:b})): placeholder{:b}mencetak nilai dalam bentuk biner, sehingga6tampil sebagai110. - Baris 10 (
(izin_gabungan & izin_baca) != 0): operator&menyaring bit milikizin_bacadariizin_gabungan; hasil4(bukan nol) membuktikan izin baca melekat, sehingga perbandingan menghasilkantrue. - Baris 11 (
(izin_gabungan & 0b1000) != 0): mask0b1000menguji bit izin hapus yang memang tidak pernah dinyalakan, sehingga hasil AND-nya0dan perbandingan bernilaifalse.
Operator ^ (XOR) punya sifat khusus yang berguna: meng-XOR-kan sebuah bit dengan 1 akan membalik status bit itu. Teknik ini dipakai untuk menyalakan-mematikan sakelar:
fn main() {
let mode_dasar: u8 = 0b0100;
let sakelar: u8 = 0b0100;
let mode_baru = mode_dasar ^ sakelar;
println!("Mode dasar: {:b}", mode_dasar);
println!("Mode baru : {:b} ({})", mode_baru, mode_baru);
let satu_bit: u8 = 1;
let nilai_besar: u8 = 200;
println!("1 << 3 = {}", satu_bit << 3);
println!("200 >> 4 = {}", nilai_besar >> 4);
}Output yang Dihasilkan:
Mode dasar: 100
Mode baru : 0 (0)
1 << 3 = 8
200 >> 4 = 12Mari kita telaah hasilnya:
- Baris 4 (
let mode_baru = mode_dasar ^ sakelar;): kedua nilai memiliki bit yang sama-sama menyala di posisi yang sama, sehingga XOR menghasilkan0; sakelar berhasil mematikan mode. - Baris 12 (
satu_bit << 3): geser kiri memindahkan bit1tiga posisi menjadi0b1000alias8; setiap geser satu langkah sama dengan mengalikan dua. - Baris 13 (
nilai_besar >> 4): geser kanan membuang empat bit terbawah dari200sehingga tersisa12; setiap geser satu langkah sama dengan membagi dua dan memotong sisanya.
Ringkasan #
Operator logika &&, ||, dan ! bekerja pada bool dengan evaluasi short-circuit yang menyelamatkan ekspresi seperti pemeriksaan pembagi nol. Operator bitwise &, |, ^, !, <<, dan >> mengoperasikan integer bit demi bit tanpa short-circuit, dan cocok untuk mask izin, sakelar bit, serta pergeseran yang setara perkalian atau pembagian dua. Simbol && dan & terlihat serupa, tetapi pilihan yang salah di antara keduanya mengubah hasil dan keselamatan program. Selanjutnya kita belajar mengonversi tipe data secara eksplisit dengan kata kunci as.