unwrap dan expect memperlakukan kegagalan sebagai ledakan; sering kali yang kita inginkan justru sebaliknya — kegagalan yang tenang. Server yang membaca port dari berkas konfigurasi tidak perlu mati hanya karena teks portnya rusak: nilai cadangan 3000 sudah cukup untuk tetap hidup. Formulir yang gagal membaca usia bisa lanjut dengan nilai bawaan. Kebutuhan “beri aku isinya, atau pakai nilai ini kalau gagal” dijawab oleh satu keluarga method pada Result: unwrap_or, unwrap_or_else, dan unwrap_or_default. Ketiganya mengembalikan nilai tipe T — bukan Result — tanpa pernah panic. Pada chapter ini kita akan memakai ketiganya pada kasus konfigurasi dan formulir, lalu membahas satu jebakan evaluasi yang membedakan kapan memilih yang mana.
unwrap_or: Nilai Cadangan Sederhana #
Method unwrap_or(nilai) adalah anggota paling sederhana: bila Result berisi Ok, isinya keluar; bila berisi Err, argumen yang kita kirimkan keluar. Program berikut membaca port server dari dua teks konfigurasi — satu sehat, satu rusak:
fn main() {
let port_benar = "8080";
let port_salah = "80delapan";
let port: u16 = port_benar.parse().unwrap_or(3000);
println!("Port dari konfigurasi valid : {}", port);
let port_cadangan: u16 = port_salah.parse().unwrap_or(3000);
println!("Port dari konfigurasi rusak : {}", port_cadangan);
}Output yang Dihasilkan:
Port dari konfigurasi valid : 8080
Port dari konfigurasi rusak : 3000Mari kita bedah kode di atas:
- Baris 5 (
port_benar.parse().unwrap_or(3000)): teks"8080"berhasil diparse menjadiOk(8080), sehinggaunwrap_ormengeluarkan8080; argumen3000terbuang percuma. - Baris 8 (
port_salah.parse().unwrap_or(3000)): teks"80delapan"menghasilkanErr, sehinggaunwrap_ormengabaikan isi error dan mengeluarkan argumen3000sebagai nilai cadangan. - Anotasi
u16pada kedua variabel: nilai kembalianunwrap_orbertipeu16— bukanResult<u16, ParseIntError>— karena kedua jalur (sukses dan cadangan) berakhir pada tipe yang sama. Program berjalan penuh tanpa panic di kedua kasus.
Perhatikan pilihan kata yang tepat: nilai 3000 adalah cadangan, bukan koreksi. Method ini tidak memperbaiki kegagalan; method hanya memastikan pekerjaan tetap berjalan dengan nilai pengganti. Konsekuensinya, informasi kegagalannya hilang — kita tidak tahu dari nilai akhir apakah parsing sukses atau tidak.
unwrap_or_else: Nilai Cadangan yang Dihitung #
Kadang nilai cadangan tidak cukup ditebalkan begitu saja — kita ingin mencatat kejadiannya, atau menghitung cadangan dari informasi error. Method unwrap_or_else(f) menerima sebuah closure — fungsi anonim dengan sintaks |parameter| isi — yang hanya dijalankan ketika Err benar-benar terjadi. Closure akan dibahas tuntas pada section Closure; untuk saat ini, bentuk |error| { ... } cukup kita pahami sebagai “fungsi kecil yang menerima error dan menghasilkan nilai cadangan”:
fn main() {
let inputs = ["36", "abc"];
for input in inputs {
let usia: u32 = input.parse().unwrap_or_else(|error| {
println!("Peringatan: input '{}' tidak valid ({})", input, error);
18
});
println!("Usia yang dipakai untuk '{}': {}", input, usia);
}
}Output yang Dihasilkan:
Usia yang dipakai untuk '36': 36
Peringatan: input 'abc' tidak valid (invalid digit found in string)
Usia yang dipakai untuk 'abc': 18Mari kita telaah kode di atas:
- Baris 5 (
input.parse().unwrap_or_else(|error| { ... })): closure|error| ...menerima isiErrsebagai parametererror. Teks"36"sukses, sehingga closure sama sekali tidak dieksekusi dan36langsung keluar. - Baris 6 (
println!("Peringatan: ...")): baris ini berada di dalam closure, dieksekusi hanya saat kegagalan. Pesan peringatan memuat teks masukan dan isi error — informasi yang sebelumnya hilang padaunwrap_orkini tercatat. - Baris 7 (
18): ekspresi terakhir closure menjadi nilai kembalian cadangan; tipeu32cocok dengan tipe sukses sehingga kedua jalur bertemu diu32. - Baris 9 (
println!("Usia yang dipakai ...")): tercetak untuk kedua iterasi — bukti program tetap hidup melewati kegagalan parsing.
Closure di sini juga menangkap variabel input dari sekitarnya untuk dibaca di dalam pesan peringatan — kemampuan standar closure yang akan kita bahas mendasar pada section Closure.
unwrap_or_default: Nilai Bawaan Tipe #
Anggota ketiga menjawab pertanyaan: bagaimana kalau nilai cadangan terbaik hanyalah “nilai awal tipe ini”? Method unwrap_or_default() tidak menerima argumen sama sekali; method meminta nilai bawaan dari trait Default milik tipe T — angka menjadi 0, String menjadi "", koleksi menjadi kosong. Program berikut membaca skor dari teks:
fn main() {
let inputs = ["90", "sembilan puluh"];
for input in inputs {
let skor: u32 = input.parse().unwrap_or_default();
println!("Skor dari '{}': {}", input, skor);
}
}Output yang Dihasilkan:
Skor dari '90': 90
Skor dari 'sembilan puluh': 0Bedah singkatnya: teks "90" berhasil menjadi Ok(90) dan keluar langsung, sedangkan teks "sembilan puluh" menghasilkan Err sehingga unwrap_or_default menghasilkan 0 — nilai Default untuk u32. Method ini paling tepat ketika nol atau kosong memang bermakna “belum ada data”, misalnya skor yang belum terisi sebelum pengguna menyimpan formulir.
Jebakan Evaluasi: unwrap_or Selalu Menyiapkan Cadangan #
Ketiga anggota keluarga ini dibedakan bukan hanya gaya, tetapi juga waktu nilai cadangan disiapkan. Argumen unwrap_or(nilai) dievaluasi lebih dulu — apa adanya — sebelum method memutuskan jalurnya, meskipun hasil akhirnya tidak dipakai. Program berikut membuktikannya:
fn hitung_cadangan() -> u16 {
println!("Menghitung port cadangan...");
3000
}
fn main() {
let port: u16 = "8080".parse().unwrap_or(hitung_cadangan());
println!("Port aktif: {}", port);
}Output yang Dihasilkan:
Menghitung port cadangan...
Port aktif: 8080Meskipun parsing "8080" sukses dan hasil akhirnya 8080, fungsi hitung_cadangan tetap terpanggil — baris Menghitung port cadangan... tercetak lebih dulu. Argumen method di Rust dievaluasi sebelum method berjalan, dan unwrap_or tidak punya hak menundanya. Sebaliknya, closure pada unwrap_or_else hanya dieksekusi ketika Err terjadi, dan unwrap_or_default tidak menyiapkan apa pun di sisi pemanggil.
Ringkasan #
Keluarga unwrap_or menjawab kegagalan dengan nilai cadangan, bukan panic: unwrap_or(nilai) memakai argumen apa adanya, unwrap_or_else(|error| ...) menjalankan closure yang bisa membaca isi error dan hanya dieksekusi saat gagal, serta unwrap_or_default() memakai nilai Default tipe seperti 0 untuk u32. Ketiganya mengembalikan T langsung dan menjaga program tetap hidup. Jebakan utamanya adalah unwrap_or yang mengevaluasi argumennya selalu — gunakan unwrap_or_else untuk cadangan yang mahal. Keluarga ini menuntaskan kebutuhan “gagal lalu ganti nilai”; bab berikutnya membahas kebutuhan yang lebih halus: mengubah isi Ok atau Err tanpa membuka bungkus Result sama sekali, lewat map dan map_err.