Thông thường, nếu một thư viện có loại chung Foo<T>
, các thùng phía dưới không thể thực hiện các đặc điểm trên đó, ngay cả khi T
là một loại cục bộ. Ví dụ,
( 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)
}
}
Đối với một ví dụ cụ thể hoạt động trên sân chơi (nghĩa là có lỗi),
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)
}
}
(sân chơi)
Điều này thường cho phép tác giả thùng thêm (triển khai) các đặc điểm mà không phá vỡ các thùng phía dưới. Điều đó thật tuyệt vời trong trường hợp ban đầu không chắc chắn rằng một loại sẽ thực hiện một đặc điểm cụ thể, nhưng sau đó nó trở nên rõ ràng rằng nó nên. Ví dụ: chúng ta có thể có một số loại số ban đầu không triển khai các đặc điểm từ đó num-traits
. Những đặc điểm này có thể được thêm vào sau mà không cần thay đổi đột phá.
Tuy nhiên, trong một số trường hợp, tác giả thư viện muốn các thùng phía dưới có thể tự thực hiện các đặc điểm. Đây là nơi #[fundamental]
thuộc tính xuất hiện. Khi được đặt trên một loại, bất kỳ đặc điểm nào hiện không được triển khai cho loại đó sẽ không được thực hiện (cấm thay đổi vi phạm). Kết quả là, các thùng hạ lưu có thể thực hiện các đặc điểm cho loại đó miễn là tham số loại là cục bộ (có một số quy tắc phức tạp để quyết định loại tham số nào được tính cho điều này). Vì loại cơ bản sẽ không thực hiện một đặc điểm nhất định, nên đặc điểm đó có thể được thực hiện tự do mà không gây ra vấn đề kết hợp.
Ví dụ, Box<T>
được đánh dấu #[fundamental]
, do đó đoạn mã sau (tương tự như Rc<T>
phiên bản trên) hoạt động. Box<T>
không thực hiện Default
(trừ khi T
thực hiện Default
) vì vậy chúng tôi có thể cho rằng nó sẽ không trong tương lai vì Box<T>
là cơ bản. Lưu ý rằng việc thực hiện Default
cho Bar
sẽ gây ra vấn đề, kể từ đó Box<Bar>
đã cụ Default
.
struct Bar;
impl Default for Box<Bar> {
fn default() -> Self {
Box::new(Bar)
}
}
(sân chơi)
Mặt khác, các đặc điểm cũng có thể được đánh dấu bằng #[fundamental]
. Điều này có một ý nghĩa kép cho các loại cơ bản. Nếu bất kỳ loại nào hiện không thực hiện một đặc điểm cơ bản, có thể giả định rằng loại đó sẽ không thực hiện nó trong tương lai (một lần nữa, ngăn chặn một sự thay đổi đột phá). Tôi không chắc chắn chính xác làm thế nào điều này được sử dụng trong thực tế. Trong mã (được liên kết bên dưới), FnMut
được đánh dấu cơ bản với ghi chú rằng nó cần thiết cho regex (một cái gì đó về &str: !FnMut
). Tôi không thể tìm thấy nơi nó được sử dụng trong regex
thùng hoặc nếu nó được sử dụng ở nơi khác.
Về lý thuyết, nếu Add
đặc điểm được đánh dấu cơ bản (đã được thảo luận) thì điều này có thể được sử dụng để thực hiện bổ sung giữa những thứ chưa có. Ví dụ, thêm [MyNumericType; 3]
(theo chiều), có thể hữu ích trong một số tình huống nhất định (tất nhiên, làm [T; N]
cơ bản cũng sẽ cho phép điều này).
Các loại cơ bản nguyên thủy là &T
, &mut T
(xem ở đây để trình diễn tất cả các loại nguyên thủy chung). Trong thư viện tiêu chuẩn, Box<T>
và Pin<T>
cũng được đánh dấu là cơ bản.
Các đặc điểm cơ bản trong thư viện chuẩn được Sized
, Fn<T>
, FnMut<T>
, FnOnce<T>
và Generator
.
Lưu ý rằng #[fundamental]
thuộc tính hiện không ổn định. Vấn đề theo dõi là vấn đề # 29635 .
&T
,&mut T
,*const T
,*mut T
,[T; N]
,[T]
,fn
con trỏ và các bộ. Và kiểm tra tất cả chúng (xin vui lòng cho tôi biết nếu mã này không có ý nghĩa) có vẻ như các tài liệu tham khảo là loại nguyên thủy cơ bản duy nhất . Hấp dẫn. Tôi sẽ quan tâm đến việc biết lý do tại sao những người khác không, đặc biệt là con trỏ thô. Nhưng đó không phải là phạm vi của câu hỏi này, tôi đoán vậy.