impl Trait
impl Trait
mirip seperti generics. Kita semua ingat bahwa generics menggunakan type T
(atau nama lainnya) yang kemudian akan ditentukan saat program dikompilasi. Pertama, kita lihat dulu sebuah concrete type:
fn gives_higher_i32(one: i32, two: i32) { let higher = if one > two { one } else { two }; println!("{} is higher.", higher); } fn main() { gives_higher_i32(8, 10); }
Hasilnya adalah: 10 is higher.
.
Tapi ia hanya akan mengambil i32
, jadi kita akan membuatnya menjadi generic. Kita perlu untuk membandingkan dan kita perlu mencetaknya menggunakan {}
, sehingga type T memerlukan PartialOrd
dan Display
. Ingat, ini berarti "hanya mengambil type yang sudah memiliki PartialOrd
dan Display
".
use std::fmt::Display; fn gives_higher_i32<T: PartialOrd + Display>(one: T, two: T) { let higher = if one > two { one } else { two }; println!("{} is higher.", higher); } fn main() { gives_higher_i32(8, 10); }
Sekarang mari kita lihat impl Trait
, yang mana mirip dengan generic. Alih-alih menggunakan type T
, kita bisa membawa traitnya menggunakan type impl Trait
. Kemudian ia akan mengambil type yang mengimplementasikan trait tersebut. Penggunaan keduanya benar-benar hampir sama:
fn prints_it(input: impl Into<String> + std::fmt::Display) { // Ambil apapun yang kembaliannya bisa diubah menjadi String dan memiliki Display println!("You can print many things, including {}", input); } fn main() { let name = "Tuon"; let string_name = String::from("Tuon"); prints_it(name); prints_it(string_name); }
Bagian menariknya adalah kita bisa me-return impl Trait
, dan ini memungkinkan kita untuk me-return closure karena function signatures mereka adalah trait. Anda bisa melihat ini pada beberapa signature di method tertentu. Contohnya, ini adalah signature dari method .map()
:
#![allow(unused)] fn main() { fn map<B, F>(self, f: F) -> Map<Self, F> // 🚧 where Self: Sized, F: FnMut(Self::Item) -> B, { Map::new(self, f) } }
fn map<B, F>(self, f: F)
berarti bahwa ia mengambil dua type generic. F
adalah function yang mengambil satu item dari container yang mengimplementasikan .map()
dan B
adalah type kembalian dari function tersebut. Kemudian setelah where
kita melihat trait bound. ("Trait bound" berarti "ia haruslah memiliki trait tersebut".) Self haruslah bertype Sized
, dan selanjutnya adalah closure signature. Ia haruslah bertype FnMut
, dan menggunakan closurenya pada Self::Item
, yang mana adalah iterator yang kita berikan. Kemudian ia me-return B
.
Jadi, kita bisa melakukan sesuatu yang sama untuk me-return sebuah closure. Untuk me-return closure, gunakan impl
dan kemudian closure signaturenya. Setelah Anda me-return hal itu, Anda bisa menggunakannya persis seperti function. Ini adalah contoh kecil dari function yang memberi Anda sebuah closure tergantung pada text yang Anda masukkan. Jika Anda memasukkan "double" atau "triple" ke dalamnya, maka ia akan mengalikannya dengan 2 atau 3, dan sebaliknya ia akan memberimu angka yang sama. Karena ini adalah closure, kita bisa melakukan apapun yang kita mau, termasuk mencetap outputnya.
fn returns_a_closure(input: &str) -> impl FnMut(i32) -> i32 { match input { "double" => |mut number| { number *= 2; println!("Doubling number. Now it is {}", number); number }, "triple" => |mut number| { number *= 40; println!("Tripling number. Now it is {}", number); number }, _ => |number| { println!("Sorry, it's the same: {}.", number); number }, } } fn main() { let my_number = 10; // buat 3 buah closure let mut doubles = returns_a_closure("double"); let mut triples = returns_a_closure("triple"); let mut quadruples = returns_a_closure("quadruple"); doubles(my_number); triples(my_number); quadruples(my_number); }
Ini contoh yang agak lebih panjang. Bayangkan ada sebuah game di mana karakter Anda menghadapi monster yang lebih kuat di malam hari. Kita bisa membuat sebuah enum bernama TimeOfDay
sebagai representasi waktu. Karakter Anda bernama Simon dan memiliki angka yang bernama character_fear
, yang bertype f64
. Nilainya akan meningkat di malam hari dan akan turun pada siang hari. Kita akan membuat function change_fear
yang nantinya akan mengubah ketakutannya, namun juga melakukan hal lain, seperti melakukan print. Codenya seperti berikut:
enum TimeOfDay { Dawn, Day, Sunset, Night, } fn change_fear(input: TimeOfDay) -> impl FnMut(f64) -> f64 { // Function mengambil TimeOfDay sebagai parameternya dan ia mengembalikan closure. // Kita menggunakan impl FnMut(64) -> f64 untuk mengatakan bahwa ia perlu mengubah // nilainya dan juga mengembalikan type yang sama use TimeOfDay::*; // Kita hanya tinggal menulis Dawn, Day, Sunset, Night // Daripada TimeOfDay::Dawn, TimeOfDay::Day, dst. match input { Dawn => |x| { // Ini adalah variabel character_fear yang akan kita berikan sebagai inputan println!("The morning sun has vanquished the horrible night. You no longer feel afraid."); println!("Your fear is now {}", x * 0.5); x * 0.5 }, Day => |x| { println!("What a nice day. Maybe put your feet up and rest a bit."); println!("Your fear is now {}", x * 0.2); x * 0.2 }, Sunset => |x| { println!("The sun is almost down! This is no good."); println!("Your fear is now {}", x * 1.4); x * 1.4 }, Night => |x| { println!("What a horrible night to have a curse."); println!("Your fear is now {}", x * 5.0); x * 5.0 }, } } fn main() { use TimeOfDay::*; let mut character_fear = 10.0; // Inisialisasi nilai ketakutan Simon dengan 10 let mut daytime = change_fear(Day); // Buat empat buah closure disini, sehingga bisa dipanggil setiap kita ingin mengubah nilai ketakutan Simon. let mut sunset = change_fear(Sunset); let mut night = change_fear(Night); let mut morning = change_fear(Dawn); character_fear = daytime(character_fear); // Panggil closurenya pada variabel ketakutan Simon's. Ia akan memberikan pesan dan mengubah angkanya. // Pada umumnya, kita akan memiliki struct Character dan menggunakannya sebagai method, // seperti ini: character_fear.daytime() character_fear = sunset(character_fear); character_fear = night(character_fear); character_fear = morning(character_fear); }
Hasilnya adalah:
What a nice day. Maybe put your feet up and rest a bit.
Your fear is now 2
The sun is almost down! This is no good.
Your fear is now 2.8
What a horrible night to have a curse.
Your fear is now 14
The morning sun has vanquished the horrible night. You no longer feel afraid.
Your fear is now 7