A.42. Pattern Matching
Chapter ini membahas tentang pattern matching, sebuah teknik yang lebih advance dibanding seleksi kondisi biasa.
Dalam pattern matching, pengecekan dilakukan dengan melihat kecocokan suatu pola/pattern.
A.42.1. Keyword match
Keyword match
digunakan untuk pattern matching. Contoh penerapan versi sederhananya bisa dilihat berikut:
let time = "morning";
match time {
"morning" => println!("isuk"),
"afternoon" => println!("awan"),
"evening" => println!("bengi"),
_ => println!("mbuh kapan"),
}
Pada contoh di atas, time
dicek nilainya menggunakan keyword match
dengan 4 buah klausul:
- Jika value-nya
morning
, tampilkan pesanisuk
- Jika value-nya
afternoon
, tampilkan pesanawan
- Jika value-nya
evening
, tampilkan pesanbengi
- Jika tidak ada yang cocok dari klausus di atas, maka tampilkan pesan
mbuh kapan
Contoh di atas adalah ekuivalen dengan seleksi kondisi if
berikut:
let time = "morning";
if time == "morning" {
println!("isuk")
} else if time == "afternoon" {
println!("awan")
} else if time == "evening" {
println!("bengi")
} else {
println!("mbuh kapan")
}
Ada satu syarat yang harus dipenuhi dalam penerapan pattern matching, yaitu semua kondisi yang memungkinkan harus ditulis, harus lengkap. Ibarat if
yang harus ada block else
-nya.
Variabel _
digunakan sebagai else-nya block match
. Tanpa adanya kondisi _
maka besar kemungkinan block match
error jika klausulnya tidak lengkap.
◉ Menampung nilai balik match
Block statement match
bisa saja menghasilkan return value. Contohnya bisa dilihat berikut ini, hasil dari pattern matching ditampung ke variabel time_but_in_javanese
.
let time = "morning";
let time_but_in_javanese = match time {
"morning" => "isuk",
"afternoon" => "awan",
"evening" => "bengi",
_ => "mbuh kapan",
};
println!("{time_but_in_javanese}");
A.42.2. Pattern matching
Contoh di atas bisa dikategorikan sebagai seleksi kondisi biasa meskipun menggunakan keyword match
. Setelah ini kita akan pelajari macam-macam pattern/pola yang di-support dalam pattern matching di Rust.
◉ Pengecekan nilai enum
Tipe data Option adalah salah satu enum yang paling sering dipakai pada pattern matching. Enum Option
memiliki 2 enum value, Some
yang merepresentasikan sebuah nilai, dan None
yang berarti tidak ada nilai.
Pattern matching pada enum cukup mudah, caranya bisa dilihat pada contoh berikut:
let value: Option<i32> = Option::Some(5);
match value {
Some(1) => println!("one"),
Some(2) => println!("two"),
Some(x) => println!("{x} greater than two"),
_ => println!("none"),
}
Variabel value
nilainya adalah Some(5)
. Variabel tersebut dimasukkan ke block match
dengan 4 buah kondisi pengecekan:
- Jika
value
nilainyaSome(1)
, tampilkan pesanone
- Jika
value
nilainyaSome(2)
, tampilkan pesantwo
- Jika
value
nilainyaSome(x)
, tampilkan pesan{x} greater than two
- Jika tidak ada yang cocok dari klausus di atas, maka tampilkan pesan
none
Tipe Option
pasti berpotensi berisi Some
atau None
, tidak mungkin selainnya. Klausul terakhir di contoh di atas (_ => println!("none")
) terpenuhi ketika nilai value
adalah None
. Pada konteks ini mengganti _
dengan None
menjadikan klausul pada pattern matching tetap lengkap.
match value {
Some(1) => println!("one"),
Some(2) => println!("two"),
Some(x) => println!("{x} greater than two"),
None => println!("none"),
}
Lebih jelasnya mengenai
Some
danNone
dibahas pada chapter Tipe Data ➜ Option
◉ Pattern |
dan ..
Klausul pattern matching bisa berisi operasi OR
maupun IN
caranya dengan memanfaatkan operator berikut:
- Operator
|
digunakan sebagai logikaOR
- Operator
..
atau..=
digunakan sebagai logikaIN
Contoh penerapannya:
let value = 6;
match value {
1 | 2 => println!("one or two"),
3..=5 => println!("three through five"),
6 => println!("six"),
_ => println!("other number"),
}
- Jika
value
nilainya1
atau2
, tampilkan pesanone or two
- Jika
value
nilainya antara3
hingga5
, tampilkan pesanthree through five
- Jika
value
nilainya6
, tampilkan pesansix
- Jika tidak ada yang cocok dari klausus di atas, maka tampilkan pesan
other number
Pattern di atas juga bisa diterapkan dalam variabel enum value, contohnya:
let value: Option<i32> = Some(5);
match value {
Some(1 | 2) => println!("one or two"),
Some(3..=5) => println!("three through five"),
Some(6) => println!("six"),
Some(x) => println!("{x} greater than six"),
_ => println!("none"),
}
Operator
|
memiliki 2 kegunaan:
- Pada statement biasa, fungsinya adalah untuk bitwise OR.
- Pada pattern matching, fungsinya untuk OR, kegunaannya sama seperti
||
pada statement biasa.Lebih jelasnya mengenai bitwise operator dibahas pada chapter Bitwise Operation
◉ Match guard
Match guard adalah teknik menambahkan sub seleksi kondisi pada klausul match
. Contoh:
let value = Some(4);
let message = match value {
Some(x) if x % 2 == 0 => format!("number {} is even", x),
Some(x) => format!("number {} is odd", x),
None => String::new(),
};
println!("{message}");
Klausul pertama di atas, yaitu Some(x)
ditambahkan match guard if x % 2 == 0
.
◉ Binding @
Operator @
digunakan untuk menampung nilai klausul match
yang default-nya tidak bisa ditampung. Agar lebih jelas, silakan pelajari pattern matching berikut:
let value = 3;
match value {
1 | 2 => println!("one or two"),
3..=5 => println!("three through five"),
6 => println!("six"),
_ => println!("other number"),
}
Klausul 1 | 2
dan 3..=5
nilai by default tidak bisa diakses. Kita hanya tau bahwa nilai pasti antara 1
dan 2
untuk klausul 1 | 2
, dan 3 / 4 / 5
untuk klausul 3..=5
.
Nilai pasti klausul tersebut bisa ditampung menggunakan operator @
.
let value = 3;
match value {
n @ (1 | 2) => println!("one or two ({})", n),
n @ 3..=5 => println!("three through five ({})", n),
6 => println!("six"),
_ => println!("other number"),
}
Khusus untuk penggunaan
@
binding pada operator|
, pada penulisan klausul seleksi kondisinya harus diapit tanda()
.
◉ if let
Untuk memahami pattern matching menggunakan keyword if let
, silakan pelajari kode berikut terlebih dahulu.
let value: Option<i32> = Some(5);
match value {
Some(1) => println!("one"),
Some(x) => println!("{x} greater than two"),
_ => println!("none"),
}
Pattern matching di atas cukup mudah dipahami, isinya ada 2 kondisi Some
dan 1 buah else (menggunakan _
).
Block kode tersebut jika dikonversi ke bentuk if
hasilnya seperti ini:
let value = Some(5);
if let Some(1) = value {
println!("one");
} else if let Some(x) = value {
println!("{x} greater than two");
} else {
println!("none");
}
Dari sini cukup jelas kegunaan dari if let
. Meskipun menggunakan operator =
(bukan ==
) block kode seleksi kondisi di atas adalah pattern matching, yang isinya melakukan pengecekan sama persis seperti pattern matching pada kode sebelumnya.
Tambahan contoh, 2 block kode berikut adalah juga ekuivalen.
let value = 6;
match value {
1 | 2 => println!("one or two"),
3..=5 => println!("three through five"),
6 => println!("six"),
_ => println!("other number"),
}
// ... vs ...
let value = Some(5);
if let Some(1 | 2) = value {
println!("one or two");
} else if let Some(3..=5) = value {
println!("three through five");
} else if let Some(6) = value {
println!("six");
} else {
println!("other number");
}
A.42.3. Destructuring assignment
◉ Struct destructuring
Operasi destructuring (menampung item suatu tipe) bisa dilakukan menggunakan pattern matching.
Pada kode di bawah ini, variabel p
yang bertipe struct Point { x: i32, y: i32 }
dimasukkan pada block pattern matching. Item dari struct tersebut di-destructure ke variabel x
dan y
masing-masing klausul pattern matching item-nya ditampung ke variabel x
dan y
.
struct Point {
x: i32,
y: i32,
}
let p = Point { x: 0, y: 7 };
match p {
Point { x, y: 0 } => println!("x axis at {x}"),
Point { x: 0, y } => println!("y axis at {y}"),
Point { x, y } => println!("axis: ({x}, {y})")
}
- Jika
p.y
nilainya0
, tampilkan pesanx axis at {x}
- Jika
p.x
nilainya0
, tampilkan pesany axis at {y}
- Jika tidak ada yang cocok dari klausus di atas, maka tampilkan pesan
axis: ({x}, {y})
Operasi destructuring hasilnya pasti sukses, karena alasan ini keyword match
boleh tidak digunakan. Contohnya bisa dilihat pada kode berikut, variabel p
di-destructure ke variabel baru yaitu x
dan y
.
let Point { x, y } = p;
println!("x: {x}");
println!("y: {y}");
◉ Enum destructuring
Destructuring juga bisa dilakukan pada tipe data enum caranya dengan menggunakan keyword match
atau if
(wajib menggunakan salah satu keyword tersebut).
enum Color {
Black,
White,
Rgb(i32, i32, i32)
}
let color = Color::Rgb(0, 160, 255);
if let Color::Rgb(r, g, b) = color {
println!("r: {r}");
println!("g: {g}");
println!("b: {b}");
}
match color {
Color::Rgb(r, g, b) => println!("r: {r}, g: {g}, b: {b}"),
_ => println!("other color")
}
◉ Tuple destructuring
Tuple bisa di-destructure secara langsung tanpa menggunakan keyword if
atau match
.
let grades = ("A", "B", "C");
let (grade_a, grade_b, grade_c) = grades;
println!("grade_a: {grade_a}");
println!("grade_b: {grade_b}");
println!("grade_c: {grade_c}");
match grades {
(grade_a, grade_b, grade_c) => {
println!("grade_a: {grade_a}");
println!("grade_b: {grade_b}");
println!("grade_c: {grade_c}");
}
}
◉ Variabel _
Variabel _
bisa dimanfaatkan pada statement destructuring untuk menampung item yang tidak digunakan. Contoh penerapannya bisa dilihat di bawah ini. Tuple numbers
di-destructure dan hanya diambil elemen ke-2-nya.
let numbers = (2, 4, 32);
let (_, second, _) = numbers;
println!("second number: {second}");
◉ Operator ..
Operator ..
bisa digunakan untuk meng-exclude item dalam range tertentu. Sebagai contoh, tuple numbers
di-destructure dan hanya diambil nilai elemen ke-1 dan terakhirnya.
let numbers = (2, 4, 8, 16, 32);
let (first, .., last) = numbers;
println!("first number: {first}");
println!("last number: {last}");
Opeartor ..
hanya bisa digunakan pada statement destructuring di posisi tengah, awal, atau akhir (pilih salah satu). Contoh:
let (first, .., last) = numbers;
println!("first number: {first}");
println!("last number: {last}");
let (first, ..) = numbers;
println!("first number: {first}");
let (.., last) = numbers;
println!("last number: {last}");
Catatan chapter 📑
◉ Source code praktik
github.com/novalagung/dasarpemrogramanrust-example/../pattern_matching
◉ Chapter relevan lainnya
◉ Work in progress
- Pembahasan tentang
while let