Satu trait bound menyelesaikan satu kebutuhan — PartialOrd untuk membandingkan, Display untuk mencetak. Fungsi dunia nyata kerap membutuhkan beberapa jaminan sekaligus pada type parameter yang sama, ditambah beberapa type parameter dengan syarat masing-masing. Notasi deklaratifnya sederhana — tanda plus menggabungkan bound — tetapi tanda tangan cepat memanjang dan memendam nama parameter di balik daftar trait. Rust menyediakan klausa where untuk memindahkan seluruh syarat ke baris tersendiri. Chapter ini menyusun multiple bounds, membuktikan bahwa notasi inline dan where identik bagi kompilator, lalu menutup dengan kaidah pemilihan di antara keduanya.
Dua Syarat dalam Satu Bound #
Kita perluas fungsi laporan dari Chapter Trait Bound: selain menemukan nilai terbesar, fungsinya harus mencetaknya langsung dengan label. Pembandingan menuntut PartialOrd; pencetakan dengan formatter {} menuntut Display. Kedua trait digabung dengan tanda plus:
use std::fmt::Display;
fn report_largest<T: PartialOrd + Display>(label: &str, list: &[T]) {
let mut largest = &list[0];
for item in list {
if item > largest {
largest = item;
}
}
println!("{} terbesar: {}", label, largest);
}
fn main() {
let scores = [72, 85, 90, 68];
let ratings = [4.2, 3.8, 4.9, 4.5];
report_largest("Skor", &scores);
report_largest("Rating", &ratings);
}Output yang Dihasilkan:
Skor terbesar: 90
Rating terbesar: 4.9Mari kita bedah kode di atas baris per baris:
- Baris 1 (
use std::fmt::Display;):PartialOrdtinggal di prelude sehingga bisa dipakai langsung, sedangkanDisplayharus diimpor secara eksplisit daristd::fmt— kebiasaan yang juga berlaku untukDebug. - Baris 3 (
fn report_largest<T: PartialOrd + Display>(label: &str, list: &[T])): boundT: PartialOrd + Displayterbaca sebagai “T harus mengimplementasikanPartialOrdDANDisplay”. Tanda plus berarti kedua syarat wajib terpenuhi — bukan salah satu. - Baris 6 (
if item > largest {): pembandingan sah karenaPartialOrdtercantum di bound — izin yang sama dengan fungsilargestpada chapter sebelumnya. - Baris 10 (
println!("{} terbesar: {}", label, largest);): pencetakanlargestbertipe&Tsah karenaDisplaytercantum di bound — izin yang sama dengan fungsiannounceyang dulu ditolak E0277. - Baris 17-18 (dua pemanggilan):
T = i32laluT = f64— keduanya mengimplementasikanPartialOrddanDisplay, sehingga melintasi bound gabungan tanpa hambatan.
Klausa where untuk Tanda Tangan yang Panjang #
Notasi plus mulai menyulitkan begitu type parameter berjumlah lebih dari satu. Bayangkan tanda tangan dengan dua parameter — T untuk pembacaan sensor yang harus bisa dibandingkan sekaligus dicetak, dan U untuk satuan yang cukup dicetak. Ditulis inline, syarat-syarat itu menumpuk di awal deklarasi dan memendam nama parameter di belakang tumpukan trait. Klausa where memindahkan seluruh syarat ke bawah, satu baris per type parameter. Program berikut memuat kedua notasi sekaligus agar kita bisa membandingkannya secara langsung:
use std::fmt::Display;
fn report_highs_inline<T: PartialOrd + Display, U: Display>(
label: &str,
readings: &[T],
unit: &U,
) -> String {
let mut highest = &readings[0];
for reading in readings {
if reading > highest {
highest = reading;
}
}
format!("{} tertinggi: {} {}", label, highest, unit)
}
fn report_highs_where<T, U>(label: &str, readings: &[T], unit: &U) -> String
where
T: PartialOrd + Display,
U: Display,
{
report_highs_inline(label, readings, unit)
}
fn main() {
let temperatures = [29.9, 31.5, 30.2, 33.8];
let humidity = [62, 65, 58, 71];
println!("{}", report_highs_inline("Suhu", &temperatures, &"derajat"));
println!("{}", report_highs_where("Kelembapan", &humidity, &"%"));
}Output yang Dihasilkan:
Suhu tertinggi: 33.8 derajat
Kelembapan tertinggi: 71 %Mari kita bedah kode di atas baris per baris:
- Baris 3-7 (
fn report_highs_inline<T: PartialOrd + Display, U: Display>(...)): bentuk inline — semua bound menempel pada daftar type parameter. Dengan dua parameter dan bound gabungan, baris pertama deklarasi menjadi padat; parameterlabel,readings, danunitterdorong ke baris-baris berikutnya. - Baris 17-21 (
fn report_highs_where<T, U>(...) where T: PartialOrd + Display, U: Display,): bentukwhere— klausa ditempatkan setelah daftar parameter, sebelum kurung kurawal body. Setiap type parameter mendapat barisnya sendiri; daftar syarat dipisah koma. Membaca tanda tangan menjadi dua langkah yang tenang: dulu parameternya, baru syaratnya. - Baris 22-23 (body
report_highs_where): fungsi bentukwherehanya meneruskan pekerjaan ke fungsi bentuk inline. Penerusan ini berhasil justru karena kedua notasi identik di mata kompilator — syaratT: PartialOrd + DisplaydanU: Displayberdiri sama kuat di kedua fungsi, sehingga bound fungsi pemanggil memenuhi bound fungsi yang dipanggil. - Baris 29-30 (dua pemanggilan):
report_highs_inlinedipanggil denganT = f64danU = &str;report_highs_wheredipanggil denganT = i32danU = &str. Kedua jalur menghasilkan format laporan yang sama persis — bukti perilaku yang tidak berubah oleh pilihan notasi.
where juga Hidup di Blok impl #
Klausa where bukan milik fungsi saja. Blok impl untuk struct generik — yang kita pelajari pada Chapter Method Generik — boleh memakai where untuk bound yang panjang, dan bound tersebut menyempitkan instansiasi mana yang memiliki method di dalamnya:
use std::fmt::Display;
struct Locker<T> {
content: T,
}
impl<T> Locker<T>
where
T: Display,
{
fn show(&self) {
println!("Isi loker: {}", self.content);
}
}
fn main() {
let locker = Locker { content: 4582 };
locker.show();
}Output yang Dihasilkan:
Isi loker: 4582Mari kita bedah bagian penting kode di atas:
- Baris 7-10 (
impl<T> Locker<T> where T: Display,): klausawhereditempel setelah tipe yang di-impl-kan. Seluruh method di blok ini hanya tersedia untuk instansiasi yang kontennya mengimplementasikanDisplay. - Baris 11-13 (
fn show(&self)): pencetakanself.contentsah tanpa bound pada method — bound sudah dinyatakan satu kali di levelimpldan mengikat semua method di dalamnya. - Baris 17 (
let locker = Locker { content: 4582 };):i32mengimplementasikanDisplay, jadiLocker<i32>berhak memanggilshow.
Ringkasan #
Tanda plus menggabungkan trait bound sebagai syarat yang harus terpenuhi semuanya — T: PartialOrd + Display membuka pembandingan dan pencetakan sekaligus pada satu type parameter, sementara type parameter lain membawa daftar syaratnya sendiri. Klausa where memindahkan seluruh daftar syarat ke bawah tanda tangan, dan program kita membuktikan notasi inline maupun where diperlakukan identik oleh kompilator hingga ke penerusan antar-fungsi. Blok impl generik juga bisa memakai where untuk mengikat semua method dalam satu syarat bersama. Sebelum menutup section, masih ada satu pertanyaan yang berkali-kali kita singgung dan belum dijawab tuntas: apa sebenarnya yang dihasilkan kompilator dari semua kode generik ini? Chapter Monomorphisasi menjawabnya sampai ke isi berkas biner.