JRG 10 · JRG Lanjut
Kalau Jawabannya Mungkin Tidak Ada
Bagaimana JRG menangani "tidak ketemu" dan "gagal" — tanpa pernah menyerahkan nilai palsu yang kelihatan seperti jawaban.
keandalanMasalah yang diselesaikan
Apa yang harus dikembalikan sebuah fungsi pencari kalau yang dicari tidak ada? Banyak bahasa menjawab null — dan di situlah kesulitan dimulai, karena null terlihat seperti nilai biasa sampai program terlanjur memakainya.
JRG menjawab berbeda: fungsi semacam itu mengembalikan Option, yang isinya salah satu dari dua hal — Some(nilai) kalau ketemu, atau None kalau tidak.
pub fn main() {
let a = [10, 20, 30]
wok(a.first())
wok(a.get(1))
wok(a.get(99)) // di luar jangkauan -> None, bukan tebakan
}Option::Some(10)
Option::Some(20)
Option::NoneMengambil isinya dengan aman
| Cara | Kalau ada isinya | Kalau kosong |
|---|---|---|
x.unwrap_or(bawaan) | Isinya | Nilai bawaan yang kamu tentukan |
x.is_some() | true | false |
match | Cabang Some(v) | Cabang None |
pub fn main() {
let a = [10, 20, 30]
wok(a.get(1).unwrap_or(0))
wok(a.get(99).unwrap_or(0))
match a.get(99) {
Some(v) => wok("Ketemu:", v),
None => wok("Tidak ada di posisi itu")
}
}20
0
Tidak ada di posisi itupub fn main() {
let a = [10, 20]
wok(a.get(0) ?? -1)
wok(a.get(9) ?? -1)
}10
-1Result: berhasil, atau gagal dengan alasan
Kalau kegagalannya punya sebab yang perlu dijelaskan, JRG memakai Result: Ok(nilai) atau Err(alasan).
fn bagi(a: int, b: int) -> Result {
if b == 0 {
return Err("tidak bisa dibagi nol")
}
return Ok(a / b)
}
pub fn main() {
match bagi(10, 2) {
Ok(v) => wok("Hasil:", v),
Err(e) => wok("Gagal:", e)
}
match bagi(10, 0) {
Ok(v) => wok("Hasil:", v),
Err(e) => wok("Gagal:", e)
}
}Hasil: 5
Gagal: tidak bisa dibagi nolMeneruskan kegagalan dengan ?
Menulis match untuk setiap pemanggilan itu melelahkan. Tanda ? berarti: "kalau ini gagal, hentikan fungsi ini dan teruskan galatnya ke atas".
fn bagi(a: int, b: int) -> Result {
if b == 0 { return Err("bagi nol") }
return Ok(a / b)
}
fn hitung(x: int) -> Result {
let a = bagi(100, x)? // gagal di sini -> langsung keluar
let b = bagi(a, 2)?
return Ok(b)
}
pub fn main() {
wok(hitung(5))
wok(hitung(0))
}Result::Ok(10)
Result::Err(bagi nol)Kenapa bukan sekadar nil
Kalau sebuah fungsi boleh menjawab nil untuk "tidak ketemu", maka nil punya dua arti: “tidak ada” dan “ada, isinya memang kosong”. Dua keadaan berbeda dengan satu jawaban yang sama — dan program tidak bisa membedakannya.
Kuis 1
Apa yang dikembalikan [1,2].get(99)?
Tepat — None, yang harus kamu buka dulu sebelum dipakai.
JRG memakai Option untuk hal yang mungkin tidak ketemu.
Kuis 2
Apa arti ? di akhir pemanggilan fungsi?
Betul.
Yang jadi bentuk percabangan singkat di JRG adalah $.
Kuis 3
Kenapa None lebih baik daripada nil untuk "tidak ketemu"?
Tepat — dan dua arti dalam satu jawaban adalah sumber bug yang sulit dilacak.
Pikirkan: apa yang terjadi kalau nilai yang tersimpan memang nil?
Latihan mandiri
1. Tulis fungsi akar(n) yang menolak bilangan negatif memakai Result.
2. Ambil elemen ke-5 dari array berisi 3 elemen, dengan nilai cadangan 0.
if n < 0 { return Err("akar bilangan negatif") } lalu return Ok(math::sqrt(n)).a.get(5).unwrap_or(0), atau a.get(5) ?? 0.