Keyword trait[][src]

Expand description

一组类型的通用接口。

trait 就像数据类型可以实现的接口。当类型实现 trait 时,可以使用泛型或 trait 对象抽象地将其视为 trait。

Traits 可以由三个关联项组成:

  • 函数和方法
  • types
  • constants

Traits 也可能包含其他类型参数。这些类型参数或 trait 本身可以受到其他 traits 的约束。

Traits 可以用作标记或承载其他逻辑语义,这些逻辑语义不是通过其项表示的。 当一个类型实现该 trait 时,它承诺遵守其契约。 Send SyncSync 是标准库中存在的两个此类标记 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;
}
Run

Traits 可以是泛型,有约束或无约束:

trait MaybeFrom<T> {
    fn maybe_from(value: T) -> Option<Self>
    where
        Self: Sized;
}
Run

Traits 可以建立在其他 traits 的需求之上。在下面的示例中,Iteratorsupertrait,而 ThreeIteratorsubtrait:

trait ThreeIterator: std::iter::Iterator {
    fn next_three(&mut self) -> Option<[Self::Item; 3]>;
}
Run

Traits 可以在函数中用作参数:

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 object 实现所有指定的 traits 及其上级特征 (如果有)。

语法如下: dyn BaseTrait + AutoTrait1 + ... AutoTraitN. 只能使用一个 BaseTrait,因此无法编译:

trait A {}
trait B {}

let _: Box<dyn A + B>;
Run

这也不是,这是语法错误:

trait A {}
trait B {}

let _: Box<dyn A + dyn B>;
Run

另一方面,这是正确的:

trait A {}

let _: Box<dyn A + Send + Sync>;
Run

Reference 具有有关 trait 对象,它们的限制以及版本之间的差异的更多信息。

不安全的 traits

某些 traits 可能不安全实现。在 trait 声明的前面使用 unsafe 关键字进行标记:

unsafe trait UnsafeTrait {}

unsafe impl UnsafeTrait for i32 {}
Run

2015 年版和 2018 年版之间的差异

在 2015 版中,traits 不需要参数模式:

trait Tr {
    fn f(i32);
}
Run

此行为在 2018 版中不再有效。