Halo teman-teman semuanya, pada artikel sebelumnya kita sudah membahas tentang module & package di Rust. Kita melihat bagaimana cara membuat module dengan mod
, memisahkan module ke file, membuat sub-module, hingga mengenal crate, package, dan cara menggunakan crate eksternal dengan Cargo. Dengan itu, kita bisa menyusun project Rust yang lebih rapi dan terorganisir.
Kali ini, kita akan membahas topik yang sangat penting dalam pemrograman yaitu error handling atau penanganan error di Rust.
Setiap program pasti memiliki potensi untuk gagal, entah karena input yang salah, file tidak ditemukan, koneksi jaringan terputus, atau hal-hal lain di luar kendali program. Rust menawarkan pendekatan yang unik dan aman untuk menangani error, berbeda dari bahasa yang menggunakan exception.
Di Rust, error handling terbagi menjadi dua kategori:
- Unrecoverable error: error yang fatal sehingga program harus dihentikan.
- Recoverable error: error yang masih bisa ditangani sehingga program tetap bisa dilanjutkan.
Mari kita bahas satu per satu.
Unrecoverable Error dengan panic!
Rust menyediakan makro panic!
untuk menandai error fatal. Jika dipanggil, panic!
akan mencetak pesan error lalu menghentikan program.
fn main() {
panic!("Terjadi error fatal!");
}
Program ini akan langsung berhenti dengan pesan error. panic!
biasanya digunakan untuk kondisi yang tidak seharusnya terjadi dan memang tidak bisa dipulihkan.
Recoverable Error dengan Result
Seperti yang sudah kita pelajari sebelumnya, Rust menggunakan enum Result<T, E>
untuk mewakili error yang bisa ditangani.
Contoh membaca file:
use std::fs::File;
fn main() {
let file = File::open("data.txt");
match file {
Ok(f) => println!("File berhasil dibuka"),
Err(e) => println!("Terjadi error: {}", e),
}
}
Jika file ada, kita mendapatkan Ok(file)
. Jika tidak ada, kita mendapatkan Err(error)
.
Unwrap dan Expect
Kadang kita tahu bahwa operasi seharusnya berhasil, dan kita ingin langsung mengambil nilai di dalam Result
. Untuk itu ada method unwrap
dan expect
.
use std::fs::File;
fn main() {
let file = File::open("data.txt").unwrap();
println!("File berhasil dibuka: {:?}", file);
}
Jika file tidak ada, program akan panic.
Dengan expect
, kita bisa menambahkan pesan error sendiri:
use std::fs::File;
fn main() {
let file = File::open("data.txt").expect("Gagal membuka file data.txt");
println!("File berhasil dibuka: {:?}", file);
}
Operator ?
Operator ?
adalah cara ringkas untuk menyebarkan error. Jika hasilnya Ok
, nilainya dikembalikan. Jika Err
, fungsi langsung keluar dengan mengembalikan error tersebut.
use std::fs::File;
use std::io::{self, Read};
fn baca_file() -> Result<String, io::Error> {
let mut file = File::open("data.txt")?;
let mut isi = String::new();
file.read_to_string(&mut isi)?;
Ok(isi)
}
fn main() {
match baca_file() {
Ok(teks) => println!("Isi file:\n{}", teks),
Err(e) => println!("Terjadi error: {}", e),
}
}
Dengan ?
, kode menjadi lebih singkat dan tetap aman.
Menggunakan panic!
atau Result
?
- Gunakan
panic!
hanya untuk kondisi yang benar-benar tidak bisa dipulihkan.
- Gunakan
Result
untuk kasus error yang wajar dan bisa ditangani oleh pemanggil fungsi.
Pendekatan ini membuat Rust mendorong kita untuk selalu menulis kode yang eksplisit dalam menangani error.
Kesimpulan
Pada artikel ini kita sudah belajar tentang error handling di Rust. Kita mengenal panic!
untuk unrecoverable error, Result
untuk recoverable error, serta cara praktis menggunakan unwrap
, expect
, dan operator ?
.
Pada artikel berikutnya, kita akan membahas tentang Collection di Rust, seperti Vector
, HashMap
, dan HashSet
, yang sering digunakan dalam program sehari-hari.
Terima Kasih