Biasanya, jika perpustakaan memiliki tipe generik Foo<T>
, peti hilir tidak dapat menerapkan sifat itu, bahkan jikaT
adalah tipe lokal. Sebagai contoh,
( crate_a
)
struct Foo<T>(pub t: T)
( crate_b
)
use crate_a::Foo;
struct Bar;
// This causes an error
impl Clone for Foo<Bar> {
fn clone(&self) -> Self {
Foo(Bar)
}
}
Untuk contoh nyata yang bekerja di taman bermain (yaitu, memberikan kesalahan),
use std::rc::Rc;
struct Bar;
// This causes an error
// error[E0117]: only traits defined in the current crate
// can be implemented for arbitrary types
impl Default for Rc<Bar> {
fn default() -> Self {
Rc::new(Bar)
}
}
(tempat bermain)
Ini biasanya memungkinkan pembuat peti untuk menambahkan (menyelimuti) implementasi sifat-sifat tanpa melanggar peti hilir. Itu bagus dalam kasus-kasus di mana awalnya tidak pasti bahwa suatu tipe harus menerapkan sifat tertentu, tetapi kemudian menjadi jelas bahwa itu harus. Sebagai contoh, kita mungkin memiliki semacam tipe numerik yang awalnya tidak menerapkan sifat-sifat dari num-traits
. Ciri-ciri itu dapat ditambahkan kemudian tanpa perlu perubahan.
Namun, dalam beberapa kasus, penulis perpustakaan menginginkan peti hilir agar dapat menerapkan sifat-sifat itu sendiri. Di sinilah #[fundamental]
atribut masuk. Ketika ditempatkan pada suatu jenis, sifat apa pun yang saat ini tidak diterapkan untuk jenis itu tidak akan diterapkan (kecuali perubahan yang melanggar). Akibatnya, peti hilir dapat menerapkan sifat-sifat untuk tipe tersebut selama parameter tipe bersifat lokal (ada beberapa aturan rumit untuk memutuskan parameter tipe mana yang menghitung ini). Karena tipe fundamental tidak akan menerapkan sifat yang diberikan, sifat itu dapat secara bebas diimplementasikan tanpa menyebabkan masalah koherensi.
Misalnya, Box<T>
ditandai #[fundamental]
, jadi kode berikut (mirip dengan Rc<T>
versi di atas) berfungsi. Box<T>
tidak menerapkan Default
(kecuali T
mengimplementasikan Default
) sehingga kami dapat berasumsi bahwa itu tidak akan terjadi di masa depan karena Box<T>
bersifat mendasar. Perhatikan bahwa menerapkan Default
untuk Bar
akan menyebabkan masalah, sejak itu Box<Bar>
sudah mengimplementasikan Default
.
struct Bar;
impl Default for Box<Bar> {
fn default() -> Self {
Box::new(Bar)
}
}
(tempat bermain)
Di sisi lain, ciri-ciri juga dapat ditandai dengan #[fundamental]
. Ini memiliki makna ganda untuk tipe fundamental. Jika jenis apa pun saat ini tidak menerapkan sifat mendasar, dapat diasumsikan bahwa jenis itu tidak akan menerapkannya di masa mendatang (sekali lagi, kecuali perubahan yang melanggar). Saya tidak begitu yakin bagaimana ini digunakan dalam praktek. Dalam kode (tertaut di bawah), FnMut
ditandai mendasar dengan catatan bahwa itu diperlukan untuk regex (sesuatu tentang &str: !FnMut
). Saya tidak dapat menemukan di mana itu digunakan dalam regex
peti atau jika digunakan di tempat lain.
Secara teori, jika Add
sifat itu ditandai fundamental (yang telah dibahas) ini dapat digunakan untuk mengimplementasikan penambahan antara hal-hal yang belum memilikinya. Misalnya, menambahkan [MyNumericType; 3]
(menunjuk), yang dapat berguna dalam situasi tertentu (tentu saja, membuat [T; N]
fundamental juga akan memungkinkan ini).
Jenis mendasar primitif yang &T
, &mut T
(lihat di sini untuk demonstrasi semua tipe primitif generik). Di perpustakaan standar, Box<T>
dan Pin<T>
juga ditandai sebagai fundamental.
Ciri-ciri mendasar di perpustakaan standar yang Sized
, Fn<T>
, FnMut<T>
, FnOnce<T>
dan Generator
.
Perhatikan bahwa #[fundamental]
atribut saat ini tidak stabil. Masalah pelacakan adalah masalah # 29635 .
&T
,&mut T
,*const T
,*mut T
,[T; N]
,[T]
,fn
pointer dan tupel. Dan menguji semuanya (tolong katakan padaku jika kode ini tidak masuk akal) tampaknya referensi adalah satu-satunya tipe primitif mendasar . Menarik. Saya akan tertarik mengetahui alasan mengapa yang lain tidak, terutama petunjuk mentah. Tapi itu bukan ruang lingkup pertanyaan ini, saya kira.