Expand description
一组类型的通用接口。
trait
就像数据类型可以实现的接口。当一个类型要实现 trait 时,可以使用泛型或 trait 对象将其抽象地视为该 trait。
traits 可以由三个关联项组成:
- 函数和方法
- types
- constants
traits 也可能包含额外的类型参数。这些类型参数或 trait 本身可以受到其他 traits 的约束。
traits 可以作为标记,也可以携带其他逻辑语义,这些逻辑语义不是通过其项表示的。
当一个类型实现该 trait 时,它就会承诺遵守它的契约。
Send
和 Sync
就是标准库中存在的两个这样的标记 traits。
有关 traits 的更多信息,请参见 Reference。
Examples
traits 是使用 trait
关键字声明的。类型可以使用 impl
Trait
for
Type
来实现它们:
trait Zero {
const ZERO: Self;
fn is_zero(&self) -> bool;
}
impl Zero for i32 {
const ZERO: Self = 0;
fn is_zero(&self) -> bool {
*self == Self::ZERO
}
}
assert_eq!(i32::ZERO, 0);
assert!(i32::ZERO.is_zero());
assert!(!4.is_zero());
Run带有关联类型:
trait Builder {
type Built;
fn build(&self) -> Self::Built;
}
Runtraits 可以是泛型,可以有约束,也可以没有约束:
trait MaybeFrom<T> {
fn maybe_from(value: T) -> Option<Self>
where
Self: Sized;
}
Runtraits 可以建立在其他 traits 的要求之上。在下面的示例中,Iterator
是一个 supertrait,而 ThreeIterator
是一个 subtrait:
trait ThreeIterator: Iterator {
fn next_three(&mut self) -> Option<[Self::Item; 3]>;
}
Runtraits 可以在函数中作为参数使用:
fn debug_iter<I: Iterator>(it: I) where I::Item: std::fmt::Debug {
for elem in it {
println!("{elem:#?}");
}
}
// u8_len_1,u8_len_2 和 u8_len_3 是等效的
fn u8_len_1(val: impl Into<Vec<u8>>) -> usize {
val.into().len()
}
fn u8_len_2<T: Into<Vec<u8>>>(val: T) -> usize {
val.into().len()
}
fn u8_len_3<T>(val: T) -> usize
where
T: Into<Vec<u8>>,
{
val.into().len()
}
Run或作为返回类型:
fn from_zero_to(v: u8) -> impl Iterator<Item = u8> {
(0..v).into_iter()
}
Run在该位置使用 impl
关键字,函数 writer 可以将具体类型隐藏为实现细节,可以在不破坏用户代码的情况下对其进行更改。
trait 对象
trait 对象 是实现一组 traits 的另一种类型的不透明值。一个 trait 对象实现了所有指定的 traits,以及它的 supertraits (如果有的话)。
语法如下: dyn BaseTrait + AutoTrait1 + ... AutoTraitN
。
只能使用一个 BaseTrait
,因此无法编译:
这也不能,这是一个语法错误:
另一方面,这是正确的:
trait A {}
let _: Box<dyn A + Send + Sync>;
RunReference 中记录了更多关于 trait 对象的信息,以及它们的局限性和版本之间的差异。
不安全的 traits
某些 traits 可能无法安全的实现。在 trait 声明的前面,使用 unsafe
关键字进行标记:
unsafe trait UnsafeTrait {}
unsafe impl UnsafeTrait for i32 {}
Run2015 年版和 2018 年版之间的差异
在 2015 版中,traits 不需要参数模式:
此行为在 2018 版中不再有效。