Tuple mengemas beberapa nilai bertipe berbeda dalam satu kesatuan tanpa nama field, dan mengaksesnya lewat student.0 atau student.1 membuat makna kode bergantung pada hafalan posisi. Pola tuple memecahkan masalah ini dengan menguraikan setiap posisi langsung ke variabel bernama: satu baris pola, seluruh komponen terurai. Karena tuple adalah tipe komposit paling sederhana, polanya juga menjadi wadah latihan yang pas untuk kombinasi teknik sebelumnya — literal, binding, _, rentang, dan or-pattern semuanya dapat ditempatkan pada tiap posisi. Chapter ini membahas pola tuple pada let, match, perulangan for, hingga parameter fungsi, beserta galat ketika jumlah komponen pola tidak sesuai.
Memecah Tuple Menjadi Variabel #
Pola tuple menuliskan satu pola per posisi di dalam kurung, dan pencocokannya murni berdasarkan urutan: pola pertama untuk komponen pertama, pola kedua untuk komponen kedua, dan seterusnya. Bentuk paling umum adalah binding semua posisi:
fn main() {
let student = ("Budi", 87, 'A');
let (name, score, grade) = student;
println!("{} mendapat nilai {} (predikat {}).", name, score, grade);
}Output yang Dihasilkan:
Budi mendapat nilai 87 (predikat A).Mari kita bedah kode di atas:
- Baris 2 (
let student = ("Budi", 87, 'A');): tuple tiga komponen bertipe(&str, i32, char); ketiga tipe tersebutCopy, sehingga tuple keseluruhannya jugaCopy. - Baris 4 (
let (name, score, grade) = student;): pola menguraikan posisi demi posisi —"Budi"tersalin kename,87kescore, dan'A'kegrade; karena tuple bersifatCopy, variabelstudenttetap sah. - Baris 6 (
println!("{} mendapat nilai {} ...", ...);): ketiga variabel kini punya nama yang bermakna sehingga baris ini terbaca alami tanpa angka posisi.
Pola tuple juga menjadi idiom pertukaran nilai yang terkenal: let (b, a) = (a, b); menukar isi dua variabel dalam satu statement. Jumlah posisi pola wajib sama dengan jumlah komponen tuple — bagian akhir chapter ini memperlihatkan galat yang muncul apabila jumlahnya berbeda.
Menguji dan Mengabaikan Posisi Tertentu #
Setiap posisi pola tuple dapat diisi pola apa pun, bukan sekadar binding: literal menguji isi posisi, _ mengabaikannya, dan binding menampungnya. Dengan kombinasi ini, satu arm dapat menyaring kombinasi nilai yang rumit tanpa if tambahan di dalam body:
fn main() {
let request: (&str, u16, bool) = ("checkout", 502, true);
match request {
("login", 200, _) => println!("Login berhasil."),
("login", code, _) => println!("Login gagal dengan kode {}.", code),
(_, 200, _) => println!("Permintaan berhasil."),
(action, code, retried) => {
println!("{} gagal (kode {}), dicoba ulang: {}.", action, code, retried)
}
}
}Output yang Dihasilkan:
checkout gagal (kode 502), dicoba ulang: true.Mari kita telusuri pencocokan nilai ("checkout", 502, true):
- Baris 5 (
("login", 200, _) => ...): dua posisi pertama diuji literal;"checkout"tidak sama dengan"login"sehingga arm ini dilewati bahkan sebelum posisi ketiga diperiksa. - Baris 6 (
("login", code, _) => ...): masih menuntut aksi"login"pada posisi pertama — nilai kita berbeda, arm dilewati lagi. - Baris 7 (
(_, 200, _) => ...): posisi pertama bebas nilai, tetapi posisi kedua menuntut200; nilai502gagal pada uji ini. - Baris 8–10 (
(action, code, retried) => ...): arm penampung mengikat ketiga posisi —actionmenerima"checkout",codemenerima502, danretriedmenerimatrue; body arm mencetak laporan lengkapnya. - Baris 8 (arm terakhir): keberadaan arm murni binding membuat seluruh kombinasi nilai tertampung, sehingga
matchmemenuhi exhaustiveness tanpa wildcard terpisah.
Pola Tuple Bersarang #
Tuple dapat berisi tuple lain, dan or-pattern dapat ditaruh per posisi. Kedua kemampuan ini memungkinkan pola yang menggali sekaligus menyaring kombinasi tanpa memperbanyak arm:
fn main() {
let board_cell = (2, 3);
match board_cell {
(0 | 2, 1 | 3) => println!("Sel gelap di pinggir papan."),
(row, col) => println!("Sel biasa pada baris {}, kolom {}.", row, col),
}
let nested = ((1, 5), "detik");
match nested {
((0, _), unit) => println!("Timer belum berjalan ({}).", unit),
((channel, duration), unit) => {
println!("Kanal {} berjalan {} {}.", channel, duration, unit)
}
}
}Output yang Dihasilkan:
Sel gelap di pinggir papan.
Kanal 1 berjalan 5 detik.Mari kita bedah kedua pencocokan tersebut:
- Baris 5 (
(0 | 2, 1 | 3) => ...): or-pattern bekerja per posisi — posisi pertama menerima0atau2, posisi kedua menerima1atau3; tanpa bentuk ini, kombinasi yang sama menuntut empat arm terpisah. - Baris 6 (
(row, col) => ...): arm penampung mengikat kedua posisi untuk sel yang tidak lolos saringan; nilai(2, 3)sendiri lolos di arm pertama karena2dan3memenuhi kedua or-pattern. - Baris 9 (
let nested = ((1, 5), "detik");): komponen pertama adalah tuple(1, 5), komponen kedua string satuan. - Baris 12 (
((0, _), unit) => ...): pola bersarang menguji komponen pertama dengan pola tuple(0, _)— kanal harus0dan durasi diabaikan — sementara komponen kedua diikatunit. - Baris 13–14 (
((channel, duration), unit) => ...): arm kedua menggali komponen pertama menjadichanneldanduration; nilai(1, 5)memenuhinya sehingga tercetak laporan kanal lengkap dengan satuan.
Pola Tuple di for dan Parameter Fungsi #
Penguraian tuple tidak eksklusif milik let dan match. Perulangan for menerima pola langsung pada nama perulangan, sehingga setiap elemen terurai begitu diambil. Parameter fungsi juga dapat memakai pola tuple, dan argumen terurai pada saat pemanggilan:
fn main() {
let students = [("Budi", 87), ("Siti", 92), ("Agus", 64)];
for (name, score) in students {
let status = match score {
s if s >= 90 => "sangat baik",
s if s >= 70 => "baik",
_ => "perlu belajar lagi",
};
println!("{}: nilai {} ({}).", name, score, status);
}
}Output yang Dihasilkan:
Budi: nilai 87 (baik).
Siti: nilai 92 (sangat baik).
Agus: nilai 64 (perlu belajar lagi).Mari kita bedah perannya:
- Baris 2 (
let students = [...];): array berisi tiga tuple(&str, i32); karena setiap komponenCopy, elemen array jugaCopydan aman disalin per iterasi. - Baris 4 (
for (name, score) in students {): pola(name, score)ditempatkan pada posisi nama perulangan — setiap elemen terurai menjadi dua variabel sebelum badan perulangan dijalankan. - Baris 5–9 (
let status = match score { ... };): skor diolah denganmatchberguard dari chapter match Lanjutan — bukti bahwa pola tuple dan guard dapat dipakai berdampingan dalam satu alur kerja. - Baris 11 (
println!("{}: nilai {} ({}).", name, score, status);): ketiga nilai — dua hasil uraian tuple dan satu hasilmatch— dicetak bersama untuk setiap siswa.
Bentuk pada parameter fungsi memakai ide yang sama:
fn print_result((name, score): (&str, i32)) {
println!("{} mendapat nilai {}.", name, score);
}
fn main() {
print_result(("Siti", 92));
}Output yang Dihasilkan:
Siti mendapat nilai 92.Baris 1 (fn print_result((name, score): (&str, i32))) menuliskan pola tuple pada parameter: tipe (&str, i32) tetap dinyatakan penuh, sedangkan (name, score) menguraikan argumen saat fungsi dipanggil. Pola pada parameter harus selalu berhasil — argumen bertipe tuple dua komponen pasti cocok dengan pola dua posisi — dan banyak tim Rust justru lebih suka menguraikan di badan fungsi agar tanda tangan fungsi terbaca eksplisit; keduanya sah secara bahasa.
Kode yang Gagal: Jumlah Komponen Salah #
Pola tuple dengan jumlah posisi berbeda dari tuple aslinya ditolak sebelum program berjalan. Kompilator melaporkannya sebagai ketidakcocokan tipe karena pola dan nilai harus memiliki bentuk yang sama:
fn main() {
let measurement = (10, 20, 30);
let (width, height) = measurement;
println!("{} x {}", width, height);
}Pesan error kompilator:
error[E0308]: mismatched types
--> main.rs:4:9
|
4 | let (width, height) = measurement;
| ^^^^^^^^^^^^^^^ ----------- this expression has type `({integer}, {integer}, {integer})`
| |
| expected a tuple with 3 elements, found one with 2 elements
|
= note: expected tuple `({integer}, {integer}, {integer})`
found tuple `(_, _)`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`.Pesan E0308 menjelaskan selisihnya dengan gamblang: nilai bertipe tuple tiga elemen, pola hanya menyediakan dua binding. Perbaikannya dapat memilih salah satu — mengikat komponen ketiga menjadi variabel, atau menuliskan _ pada posisi ketiga bila nilainya tidak diperlukan.
Ringkasan #
Pola tuple menguraikan komponen berdasarkan posisi: binding memberi nama pada tiap komponen, literal menguji isi posisi, _ mengabaikannya, dan or-pattern per posisi menyaring kombinasi tanpa memperbanyak arm. Pola bersarang menggali tuple di dalam tuple, for menerima pola langsung pada nama perulangan, dan parameter fungsi dapat menguraikan argumen bertipe tuple. Selisih jumlah komponen antara pola dan nilai memicu E0308 yang lengkap dengan perbandingan tipe. Setelah pola mampu menguraikan struct, enum, dan tuple, chapter berikutnya menyederhanakan satu kebutuhan yang sering muncul: menangani satu pola tertentu tanpa menulis match lengkap.