Ini sekarang disinggung dalam edisi kedua The Rust Programming Language . Namun, mari selami sedikit sebagai tambahan.
Mari kita mulai dengan contoh yang lebih sederhana.
Kapan tepat menggunakan metode sifat?
Ada beberapa cara untuk memberikan penjilidan terlambat :
trait MyTrait {
fn hello_word(&self) -> String;
}
Atau:
struct MyTrait<T> {
t: T,
hello_world: fn(&T) -> String,
}
impl<T> MyTrait<T> {
fn new(t: T, hello_world: fn(&T) -> String) -> MyTrait<T>;
fn hello_world(&self) -> String {
(self.hello_world)(self.t)
}
}
Dengan mengabaikan strategi implementasi / kinerja apa pun, kedua kutipan di atas memungkinkan pengguna untuk menentukan secara dinamis bagaimana hello_world
seharusnya berperilaku.
Satu perbedaan (secara semantik) adalah bahwa trait
implementasi menjamin bahwa untuk tipe tertentu yang T
mengimplementasikan trait
, hello_world
akan selalu memiliki perilaku yang sama sedangkan struct
implementasi memungkinkan memiliki perilaku yang berbeda pada basis per contoh.
Apakah menggunakan metode itu tepat atau tidak tergantung pada kasus penggunaan!
Kapan waktu yang tepat untuk menggunakan tipe terkait?
Mirip dengan trait
metode di atas, tipe terkait adalah bentuk pengikatan akhir (meskipun terjadi saat kompilasi), yang memungkinkan pengguna trait
untuk menentukan jenis yang akan diganti untuk instance tertentu. Ini bukan satu-satunya cara (jadi pertanyaannya):
trait MyTrait {
type Return;
fn hello_world(&self) -> Self::Return;
}
Atau:
trait MyTrait<Return> {
fn hello_world(&Self) -> Return;
}
Setara dengan metode pengikatan akhir di atas:
- yang pertama memaksakan bahwa untuk yang diberikan
Self
ada satu yang Return
terkait
- yang kedua, sebaliknya, memungkinkan menerapkan
MyTrait
untuk Self
untuk beberapaReturn
Bentuk mana yang lebih tepat bergantung pada apakah masuk akal untuk menegakkan kesatuan atau tidak. Sebagai contoh:
Deref
menggunakan tipe yang diasosiasikan karena tanpa unicity compiler akan menjadi gila selama inferensi
Add
menggunakan tipe terkait karena pembuatnya berpikir bahwa dengan dua argumen akan ada tipe pengembalian logis
Seperti yang Anda lihat, meskipun Deref
merupakan kasus penggunaan yang jelas (kendala teknis), kasusnya Add
kurang jelas: mungkin masuk akal untuk i32 + i32
menghasilkan salah satu i32
atau Complex<i32>
bergantung pada konteksnya? Meskipun demikian, penulis menjalankan penilaian mereka dan memutuskan bahwa kelebihan jenis pengembalian untuk penambahan tidak diperlukan.
Pendapat pribadi saya adalah bahwa tidak ada jawaban yang benar. Namun, di luar argumen unicity, saya akan menyebutkan bahwa tipe terkait membuat penggunaan sifat lebih mudah karena mereka mengurangi jumlah parameter yang harus ditentukan, jadi jika manfaat dari fleksibilitas menggunakan parameter sifat biasa tidak jelas, saya menyarankan untuk memulai dengan jenis yang terkait.
trait/struct MyTrait/MyStruct
memungkinkan tepat satuimpl MyTrait for
atauimpl MyStruct
.trait MyTrait<Return>
memungkinkan beberapaimpl
karena bersifat umum.Return
bisa tipe apapun. Struct generik sama.Jenis terkait adalah mekanisme pengelompokan , sehingga harus digunakan jika memungkinkan untuk mengelompokkan jenis bersama.
Ciri yang
Graph
diperkenalkan dalam dokumentasi adalah contohnya. Anda ingin aGraph
menjadi generik, tetapi setelah Anda memiliki jenis tertentuGraph
, Anda tidak ingin jenisNode
atauEdge
bervariasi lagi. Seorang tertentuGraph
tidak akan ingin memvariasikan jenis-jenis itu dalam satu implementasi, dan pada kenyataannya, ingin mereka selalu sama. Mereka dikelompokkan bersama, atau bahkan bisa dikatakan terkait .sumber