"Sebenarnya ada apa dengan postingan ini? saya sedang belajar rust lang. Metode yang menurut saya efektif untuk belajar adalah menuliskannya di blog dan menjelaskannya kembali. Saya amat sangat menerima kritik dan saran."
Intro
Post terakhir saya mengenai Rust kurang lebih 4 bulan yang lalu mengenai null value, sudah lama sekali saya tidak belajar mengenai bahasa kepiting ini. Hal yang saya rasakan pertama kali adalah “blank” seperti orang yang lupa segalanya (lebay coy). Akhirnya saya memutuskan kembali belajar rust. Oleh sebab itu, sekarang anda sedang membaca tulisan saya.
The book
matchthat allows you to compare a value against a series of patterns and then execute code based on which pattern matches.
Match adalah fitur pada bahasa pemrograman rust yang amat sangat berguna, bisa saja sepanjang karir menggunakan bahasa ini, kita tak lepas dari match. Keistimewaanya terletak pada kemampuan match dalam mengidentifikasi berbagai macam pola untuk melakukan eksekusi kode berdasarkan pola yang cocok.

Bayangkan sebuah mesin pemilah koin untuk memisahkan berdasarkan jenis, ukuran, dan kriteria fisik lainnya. Tentunya koin yang akan terpilih sesuai dengan kriterianya masing-masing. Tidak akan ada cerita dimana koin x tertukar dengan koin y.
Catatan: Apabila suatu kata memiliki background abu-abu dan bercetak tebal, maka kata tersebut adalah sebuah syntax/kode.
Main Content
Study Case
Misalnya terdapat suatu koin dari beberapa kerajaan di Indonesia, yaitu koin Kerajaaan Majapahit, Sriwijaya, Ternate, Cirebon, dan Tidore. Kita akan menuliskan sebuah program yang dapat memberikan nilai koin tersebut dalam rupiah.
enum Koin{
Majapahit,
Sriwijaya,
Ternate,
Tidore,
Cirebon,
}
fn nilai_dalam_rupiah(koin: Koin) -> u32 {
match koin {
Koin::Majapahit => 1000,
Koin::Sriwijaya => 2000,
Koin::Ternate => 3000,
Koin::Tidore => 4000,
Koin::Cirebon => 5000,
}
}
fn main() {
let koin1 = Koin::Majapahit;
println!("Nilai koin Majapahit: {} rupiah",
nilai_dalam_rupiah(koin1));
}Contoh 1.0 Penerapan match control flow
Struktur penggunaan match HAMPIR sama dengan if, tetapi terdapat perbedaan karena if akan mengevaluasi suatu kondisi berdasarkan boolean value (true atau false). Sedangkan match dapat mengevaluasi suatu kondisi dengan tipe yang lebih luas, dalam contoh ini adalah enum Koin.
match koin {
// Arm 1
Koin::Majapahit => 1000
// Arm 2
Koin::Sriwijaya => 2000,
// Arm 3
Koin::Ternate => 3000,
// Arm 4
Koin::Tidore => 4000,
// Arm 5
Koin::Cirebon => 5000,
}Contoh 1.1 arms
match memiliki sebuah fitur yang bernama arms dengan struktur:
pola +operator(=>) + kode
Pola yang kita gunakan adalah Koin::Majapahit dengan kode berupa angka (u32), yaitu 1000. Setiap arm dipisahkan dengan menggunakan tanda “,“.
Nilai koin Majapahit: 1000 rupiah
Nilai koin Tidore: 4000 rupiahContoh 1.2 output dari kode yang ditulis
Saat match berjalan maka perbandingan dilakukan dari arm 1 – arm 5, jika terdapat arm yang cocok maka kode dieksekusi. Apabila arm 1 tidak cocok akan diteruskan secara berurutan sampai arm 5. Pada contoh 1.1 kita hanya menggunakan kode sederhana berupa angka pada setiapa arm, bilamana kita ingin memasukan lebih dari 1 kode maka diharuskan menggunakan {}.
Pattern yang Ditambah Value
Terdapat dua jenis koin Kerajaan Majapahit, yaitu koin yang berasal dari wilayah Utara dan Selatan. Bagaimana jika kita ingin mengetahui asal daerah koin Majapahit agar tidak tertukar? jawabannya adalah menambahkan value pada pattern match.
// Membuat enum baru untuk wilayah asal dari koin Majapahit
#[derive(Debug)]
enum MajapahitLoc {
Selatan,
Utara,
}
enum Koin{
Majapahit(MajapahitLoc),
Sriwijaya,
Ternate,
Tidore,
Cirebon,
}
fn nilai_dalam_rupiah(koin: Koin) -> u32 {
match koin {
Koin::Sriwijaya => 2000,
Koin::Ternate => 3000,
Koin::Tidore => 4000,
Koin::Cirebon => 5000,
// Menambahkan variabel "wilayah" pada pattern arm
Koin::Majapahit(wilayah) => {
println!("Koin ini berasal dari Majapahit {:?}!", wilayah);
1000
}
}
}
fn main() {
nilai_dalam_rupiah(Koin::Majapahit(MajapahitLoc::Utara));
}Contoh 1.3 solusi
Pertama kita membuat enum baru dengan nama MajapahitLoc yang di dalamnya terdapa wilayah Selatan dan Utara. Kemudian dibagian arm pattern 5 yang awalnya hanya Coin::Majapahit ditambahkan variabel wilayah sehingga menjadi Coin::Majapahit(wilayah) =>.
Pada saat arm 5 cocok maka variabel tersebut akan terhubung dengan asal wilayah koin Majapahit. Kita juga bisa menggunakan variabel wilayah yang telah memiliki nilai tersebut pada kode.
Coin::Majapahit(wilayah) => {
println!("Koin ini berasal dari Majapahit {:?}!", wilayah);
1000
}Contoh 1.4 menggunakan variabel dari pattern
Perhatikan output dari kode yang telah kita tulis pada contoh 1.3, hasilnya adalah kita mengetahui asal wilayah koin tersebut. Tadaaa, selamat telah membuat contoh sederhana dari sorting-machine.
Koin ini berasal dari Majapahit Utara!Contoh 1.5 output
Menggunakan Option<T> Arm Pattern
fn main() {
fn tambah_satu (x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i+1),
}
}
let five = Some(5);
let six = tambah_satu(five);
let none = tambah_satu(None);
println!("Six {:?} dan none = {:?}", six, none);
}Contoh 1.6 matching with option <T>
Pada contoh 1.6 kita menggunakan inner function (berada dalama fungsi utama fn main), yaitu fn tambah_satu yang akan menerima value Option<i32> menggunakan variabel x. Nilai tersebut berasal dari variabel let five.
Pemindahan value pada fungsi fn tambah_satu menggunakan dua variabel baru, yaitu let six dan let none. Value dari dua variabel tersebut adalah tambah_satu(five) dan tambah_satu(None).
Six Some(6) dan none = NoneContoh 1.7 Output code
Match si Perfeksionis
fn main() {
fn tambah_satu (x: Option<i32>) -> Option<i32> {
match x {
Some(i) => Some(i+1),
}
}
let five = Some(5);
let six = tambah_satu(five);
let none = tambah_satu(None);
}Contoh 1.8 macth yang benar-benar perfeksionis
Judul bagian ini hanya candaan, arm pattern match haruslah mencakup semua kemungkinan yang terjadi (lengkap). Oleh karena itu, jika kita mencoba menjalankan kode pada contoh 1.8 akan terjadi error, mengapa bisa terjadi? rust tidak ingin membuat kesalahan fatal untuk program kita nantinya.
Compiling hello-word v0.1.0 (/home/hygge/Documents/Rust/hello-word)
warning: unused variable: `six`
--> src/main.rs:9:9
|
9 | let six = tambah_satu(five);
| ^^^ help: if this is intentional, prefix it with an underscore: `_six`
|
= note: `#[warn(unused_variables)]` on by default
warning: unused variable: `none`
--> src/main.rs:10:9
|
10 | let none = tambah_satu(None);
| ^^^^ help: if this is intentional, prefix it with an underscore: `_none`
error[E0004]: non-exhaustive patterns: `None` not covered
--> src/main.rs:3:15
|
3 | match x {
| ^ pattern `None` not coveredContoh 1.9 kode tidak bisa kita compile karena terdapat error
Perhatikan bahwa pada kode 1.8 tidak terdapat arm None => None, sehingga ketika kita menjalankan kode tersebut akan terjadi error. Hal ini terjadi karena match tidak memiliki arm untuk meng-handle sesuatu yang tidak memiliki value (None). Langkah ini juga mencegah masalah null value “the billion-dollar mistake“.
Pattern Untuk Segala Kemungkinan
Segala kemungkinan? betul sekali. Bayangkan anda adalah ketua suatu kegiatan yang akan menyiapkan doorprize dengan sistem acak menggunakan kertas berisi angka hadiah.
- Angka 3 berarti peserta mendapatkan tambahan hadiah.
- Angka 7 mendapatkan tambahan diskon.
- Selain dari angka 3 dan 7 mendapatkan tambahan cashback .
fn main(){
let kocok_dadu = 9;
match kocok_dadu {
3 => tambah_hadiah(),
7 => tambah_diskon(),
other => tambah_cashback(),
}
fn tambah_hadiah(){}
fn tambah_diskon(){}
fn tambah_cashback(num_spaces: u8){}
}Contoh 2.0 penggunaan cath alll pattern
Segala kemungkinan akan di-handle oleh arm other => tambah_cashback() berupa angka selain dari 3 dan 7. Ingat bahwa match harus dapat melakukan handling terhadap segala kemungkinan.
Bagaimana jika kita ingin pemain yang mendapatkan angka 3 dan 7 mendapatkan tulisan coba lagi?
Rust memungkinkan keinginan anda terpenuhi menggunakan garis bawah _ sehingga kodenya menjadi:
fn main(){
let kocok_dadu = 9;
match kocok_dadu {
3 => tambah_hadiah(),
7 => tambah_diskon(),
_ => tulisan_coba_lagi(),
}
fn tambah_hadiah(){}
fn tambah_diskon(){}
fn tulisan_coba_lagi(){}
}Contoh 2.0 penggunaan _
Peserta yang mendapatkan angka selain dari 3 akan mendapatkan tulisan coba lagi. Penggunaan garis bawah membuat arm tidak melakukan bind pada value apapun.
Bagaimana jika pemain yang mendapat angka selain 3 dan 7, benar-benar tidak mendapatkan apapun termasuk tulisan coba lagi?
fn main(){
let kocok_dadu = 9;
match kocok_dadu {
3 => tambah_hadiah(),
7 => tambah_diskon(),
other => (),
}
fn tambah_hadiah(){}
fn tambah_diskon(){}
}Contoh 2.0 arm yang tidak menggunakan value sama sekali
Pada contoh 2.0 menandakan bahwa kita tidak akan menggunakan semua value selain dari arm sebelumnya. Tidak ada pendekatan apapun yang dilakukan oleh arm other => (),.
Penutup
Saya ucapkan terima kasih telah membaca tulisan ini sampai bagian penutup. Komentar dan saran sangat saya hargai. Ingat pepatah china yang berkata: