Traits
Versi Bahasa Indonesia. Baca dalam Bahasa Inggris
- Trait mirip dengan interface di bahasa pemrograman lain.
- Ia mendefinisikan sekumpulan metode yang harus diimplementasikan oleh suatu tipe, memungkinkan kamu menentukan fungsionalitas apa yang disediakan suatu tipe tanpa mendikte bagaimana ia menyediakannya.
- Mengimplementasikan trait pada suatu tipe mirip dengan mengimplementasikan metode reguler.
- Perbedaannya adalah setelah
impl, kita letakkan nama trait yang ingin kita implementasikan, lalu gunakan keywordfor, dan kemudian tentukan nama tipe yang ingin kita implementasikan trait tersebut. - Traits dapat menyediakan implementasi metode default yang bisa di-override oleh tipe.
- Sintaks
impl Traitberfungsi untuk kasus yang sederhana tetapi sebenarnya adalah sintaks gula untuk bentuk yang lebih panjang yang dikenal sebagai trait bound. - Kita juga dapat menentukan lebih dari satu trait bound menggunakan sintaks
+. - Referensi:
traits1.rs
// The trait `AppendBar` has only one function which appends "Bar" to any object
// implementing this trait.
trait AppendBar {
fn append_bar(self) -> Self;
}
impl AppendBar for String {
// Implement `AppendBar` for the type `String`.
fn append_bar(self) -> Self {
self + "Bar"
}
}
fn main() {
let s = String::from("Foo");
let s = s.append_bar();
println!("s: {s}");
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_foo_bar() {
assert_eq!(String::from("Foo").append_bar(), "FooBar");
}
#[test]
fn is_bar_bar() {
assert_eq!(String::from("").append_bar().append_bar(), "BarBar");
}
}- Latihan ini mudah, kita hanya perlu mengimplementasikan item/fungsi trait
append_bardi dalam blockimpl AppendBar for String.
traits2.rs
trait AppendBar {
fn append_bar(self) -> Self;
}
// Implement the trait `AppendBar` for a vector of strings.
// `append_bar` should push the string "Bar" into the vector.
impl AppendBar for Vec<String> {
fn append_bar(mut self) -> Self {
self.push("Bar".to_string());
self
}
}
fn main() {
// You can optionally experiment here.
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_vec_pop_eq_bar() {
let mut foo = vec![String::from("Foo")].append_bar();
assert_eq!(foo.pop().unwrap(), "Bar");
assert_eq!(foo.pop().unwrap(), "Foo");
}
}-
Latihan ini juga mirip dengan yang pertama.
-
Kita perlu membuat implementasi trait
AppendBaruntukVec<String>. -
Karena kita ingin memutasi vector (
self) kita perlu menambahkan sintaksmut. -
Implementasi lengkapnya akan terlihat seperti ini:
impl AppendBar for Vec<String> { fn append_bar(mut self) -> Self { self.push("Bar".to_string()); self } }
traits3.rs
trait Licensed {
// Add a default implementation for `licensing_info` so that
// implementors like the two structs below can share that default behavior
// without repeating the function.
// The default license information should be the string "Default license".
fn licensing_info(&self) -> String {
"Default license".to_string()
}
}
struct SomeSoftware {
version_number: i32,
}
struct OtherSoftware {
version_number: String,
}
impl Licensed for SomeSoftware {} // Don't edit this line.
impl Licensed for OtherSoftware {} // Don't edit this line.
fn main() {
// You can optionally experiment here.
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_licensing_info_the_same() {
let licensing_info = "Default license";
let some_software = SomeSoftware { version_number: 1 };
let other_software = OtherSoftware {
version_number: "v2.0.0".to_string(),
};
assert_eq!(some_software.licensing_info(), licensing_info);
assert_eq!(other_software.licensing_info(), licensing_info);
}
}- Di latihan ini kita perlu membuat implementasi default dari
licensing_infoyang akan mengembalikan"Default license". - Implementasi default ini akan dipanggil jika trait tidak diimplementasikan untuk tipe yang ditentukan.
traits4.rs
trait Licensed {
fn licensing_info(&self) -> String {
"Default license".to_string()
}
}
struct SomeSoftware;
struct OtherSoftware;
impl Licensed for SomeSoftware {}
impl Licensed for OtherSoftware {}
// Fix the compiler error by only changing the signature of this function.
fn compare_license_types(software1: impl Licensed, software2: impl Licensed) -> bool {
software1.licensing_info() == software2.licensing_info()
}
fn main() {
// You can optionally experiment here.
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn compare_license_information() {
assert!(compare_license_types(SomeSoftware, OtherSoftware));
}
#[test]
fn compare_license_information_backwards() {
assert!(compare_license_types(OtherSoftware, SomeSoftware));
}
}-
Di latihan ini kita perlu mengubah signature fungsi
compare_license_typesuntuk menerima tipeSomeSoftwaredanOtherSoftware. -
Kita dapat melakukannya menggunakan generics.
-
Atau kita juga dapat menggunakan sintaks
impl Traitseperti ini:fn compare_license_types(software1: impl Licensed, software2: impl Licensed) -> bool -
Kamu dapat membaca lebih lanjut di sini: https://doc.rust-lang.org/book/ch10-02-traits.html#trait-bound-syntax
traits5.rs
trait SomeTrait {
fn some_function(&self) -> bool {
true
}
}
trait OtherTrait {
fn other_function(&self) -> bool {
true
}
}
struct SomeStruct;
impl SomeTrait for SomeStruct {}
impl OtherTrait for SomeStruct {}
struct OtherStruct;
impl SomeTrait for OtherStruct {}
impl OtherTrait for OtherStruct {}
// Fix the compiler error by only changing the signature of this function.
fn some_func(item: (impl SomeTrait + OtherTrait)) -> bool {
item.some_function() && item.other_function()
}
fn main() {
// You can optionally experiment here.
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_some_func() {
assert!(some_func(SomeStruct));
assert!(some_func(OtherStruct));
}
}-
Di latihan ini kita perlu memperbarui signature fungsi
some_funcuntuk menerima implementasi dariSomeTraitdanOtherTrait. -
Ini berarti tipe yang diberikan harus mengimplementasikan kedua trait.
-
Kita dapat melakukannya dengan menggunakan sintaks
+seperti ini:fn some_func(item: (impl SomeTrait + OtherTrait)) -> bool
Last updated on