当前位置:嗨网首页>书籍在线阅读

09-特征的多种形式

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

4.3.2 特征的多种形式

在前面的示例中,我们了解了最简单的特征形式,但这只是特征的冰山一角。当你开始接触大型代码库中的特征时,将会遇到它的多种形式。因为程序的复杂度和要解决的问题相比较,简单的特征形式可能并不适合我们使用。Rust为我们提供了其他形式的特征,可以很好地帮助我们为问题建模。我们将介绍一个标准库的特征,并尝试对它们进行分类,以便了解何时需要使用它们。

标记特征

在std::marker模块中定义的特征被称为标记特征(marker trait)。这种特征不包含任何方法,声明时只是提供特征名称和空的函数体。

标准库中的示例包括Copy、Send、Sync。它们被称为标记特征,因为它们用于简单地将类型标记为属于特定的组群,以获得一定程度的编译期保障。标准库中的两个这样的示例是Send和Sync特征,它们在适当的时候由语言为大多数类型自动实现,并确定哪些值可以安全地发送和跨线程共享。我们将在第8章对它们进行详细介绍。

简单特征

这可能是特征定义的最简单形式。我们已将它作为特征的简单定义进行了阐述:

trait Foo {
    fn foo();
}

标准库中的一个示例是Default特征,它主要是针对可以使用默认值初始化的类型实现的。

泛型特征

特征也可以是泛型。这在用户希望为多种类型实现特征的情况下非常有用:

pub trait From<T> {
    fn from(T) -> Self;
}

这样的两个例子是From和Into特征,它们允许从某种类型转换为类型T,反之亦然。当这些特征用作函数参数中的特征区间时,它们的作用尤为突出。稍后我们将会介绍特征区间及其用法。不过当使用3个或者4个泛型声明它们时,通常特征会变得非常冗长。对于这种情况,我们可以使用关联类型特征。

关联类型特征

trait Foo {
    type Out;
    fn get_value(self) -> Self::Out;
}

这是泛型特征的更好选择,因为它们能够在特征中声明相关类型,例如前面代码中特征Foo声明的Out类型。它们具有较少的类型签名,其优点在于,在实际的编程中,它们允许用户一次性声明关联类型,并在任何特征方法或函数中使用Self::Out作为返回类型或参数类型。这消除了类型的冗余声明,与泛型特征的情况类似。关联类型特征的最佳用例之一是Iterator特征,它用于迭代自定义类型的值。在第8章中,我们将会深入介绍迭代器。

继承特征

我们已经在代码示例trait_inheritance.rs中看到了这些特征。与Rust中的类型不同,特征可以具有继承关系,例如:

trait Bar {
    fn bar();
}
trait Foo: Bar {
    fn foo();
}

在上述代码片段中,我们声明了一个特征Foo,它依赖于父级特征Bar。在Foo的定义中,要求用户在为类型实现Foo特征时必须为Bar特征提供实现。标准库中的这样一个示例是Copy特征,它要求类型必须实现Clone特征。