在某个地方,我使用了“基本类型”一词(及其属性#[fundamental]
),而现在我想了解更多有关它的信息。我隐约记得它是关于在某些情况下放宽一致性规则的。而且我认为引用类型就是这种基本类型。
不幸的是,在网上搜索并没有带给我很多。 Rust参考没有提到它(据我所知)。我刚刚发现了an issue about making tuples fundamental types和the RFC that introduced the attribute。但是,RFC有一个关于基本类型的段落:
#[fundamental]
类型的Foo
是实现覆盖的一种 对Foo
的实现是一项重大变化。如上所述,&
和&mut
是 基本的。此属性将应用于Box
,使Box
在连贯性方面与&
和&mut
的行为相同。
我觉得措辞相当难以理解,感觉我需要深入了解完整的RFC,才能理解有关基本类型的知识。我希望有人可以用更简单的术语来解释基本类型(当然,不必过多简化)。这个问题也可以作为易于查找的知识。
要理解基本类型,我想回答以下问题(除了主要的“它们什至是什么?”问题,当然):
#[fundamental]
从而从某种程度上受益吗?答案 0 :(得分:33)
通常,如果一个库具有泛型类型Foo<T>
,即使T
是某种本地类型,下游的板条箱也无法在其上实现特征。例如,
({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)
}
}
对于在操场上工作的具体示例(即出现错误),
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)
}
}
这通常使板条箱作者可以添加(空白)特征的实现,而不会破坏下游板条箱。在最初不确定某个类型应实现特定特征的情况下,这很好,但后来变得很清楚,它应该实现。例如,我们可能有某种数字类型,其最初并未实现num-traits
的特征。这些特征可以在以后进行添加,而无需进行重大更改。
但是,在某些情况下,图书馆作者希望下游的板条箱能够自己实现特征。这就是#[fundamental]
属性的来源。当放置在一个类型上时,当前未为此类型实现的所有特征都将不会实现(除非有重大更改)。结果,只要类型参数是本地的,下游的板条箱就可以实现该类型的特征(有一些复杂的规则来确定为此计算哪些类型参数)。由于基本类型不会实现给定的特征,因此可以自由实现该特征而不会引起一致性问题。
例如,Box<T>
被标记为#[fundamental]
,因此以下代码(类似于上面的Rc<T>
版本)有效。 Box<T>
不实现Default
(除非T
实现Default
),所以我们可以假设它将来不会出现,因为Box<T>
是基础。请注意,为Default
实现Bar
会导致问题,因为Box<Bar>
已经实现了Default
。
struct Bar;
impl Default for Box<Bar> {
fn default() -> Self {
Box::new(Bar)
}
}
另一方面,特征也可以用#[fundamental]
标记。这对于基本类型具有双重含义。如果当前没有任何类型实现基本特征,则可以假定该类型将来不会实现(再次,除非做出重大更改)。我不确定在实践中如何使用它。在代码(链接如下)中,FnMut
被标记为基本,并指出正则表达式需要它(有关&str: !FnMut
的内容)。我找不到regex
板条箱中的位置或其他位置。
从理论上讲,如果将Add
特性标记为基本特性(已经讨论过),则可以将其用于在尚不具备的特性之间实现加法。例如,添加[MyNumericType; 3]
(逐点),这在某些情况下可能很有用(当然,使[T; N]
为基础也可以这样做)。
原始基本类型为&T
,&mut T
(有关所有通用原始类型的说明,请参见here)。在标准库中,Box<T>
和Pin<T>
也被标记为基本。
标准库的基本特征是Sized
,Fn<T>
,FnMut<T>
,FnOnce<T>
和Generator
。
请注意,#[fundamental]
属性当前不稳定。跟踪问题为issue #29635。