diff --git a/src/ch19-03-advanced-traits.md b/src/ch19-03-advanced-traits.md index a524a53..27f595a 100644 --- a/src/ch19-03-advanced-traits.md +++ b/src/ch19-03-advanced-traits.md @@ -8,9 +8,9 @@ ### 关联类型在 trait 定义中指定占位符类型 -**关联类型**(*associated types*)是一个将类型占位符与 trait 相关联的方式,这样 trait 的方法签名中就可以使用这些占位符类型。trait 的实现者会针对特定的实现在这个占位符类型指定相应的具体类型。如此可以定义一个使用多种类型的 trait,直到实现此 trait 时都无需知道这些类型具体是什么。 +**关联类型**(*associated types*)让我们可以在 trait 里面增加一个待定义的类型(类型占位符),将类型占位符与 trait 相关联,这样 trait 的方法签名中就可以使用这些占位符类型。trait 的实现者在实现这个 trait 的时候,会指定一个具体类型,来替换掉这个占位符。这样,我们可以在一个 trait 中通过占位符使用不同类型,在实现此 trait 时才需要指定这些类型具体是什么。 -本章所描述的大部分内容都非常少见。关联类型则比较适中;它们比本书其他的内容要少见,不过比本章中的很多内容要更常见。 +我们之前提到,本章所描述的大部分内容都较少使用。关联类型则比较适中;它们比本书其他的内容要少见,不过比本章中的很多内容要更常见。 一个带有关联类型的 trait 的例子是标准库提供的 `Iterator` trait。它有一个叫做 `Item` 的关联类型来替代遍历的值的类型。`Iterator` trait 的定义如示例 19-12 所示: @@ -20,9 +20,10 @@ 示例 19-12: `Iterator` trait 的定义中带有关联类型 `Item` -`Item` 是一个占位符类型,同时 `next` 方法定义表明它返回 `Option` 类型的值。这个 trait 的实现者会指定 `Item` 的具体类型,然而不管实现者指定何种类型,`next` 方法都会返回一个包含了此具体类型值的 `Option`。 +`Item` 是一个占位符类型,同时 `next` 方法的定义表明它返回 `Option` 类型的值。这个 trait 的实现者会指定 `Item` 的具体类型,无论实现者指定何种类型,`next` 方法都会返回一个包含了此具体类型值的 `Option`。 -关联类型看起来像一个类似泛型的概念,因为它允许定义一个函数而不指定其可以处理的类型。让我们通过在一个 `Counter` 结构体上实现 `Iterator` trait 的例子来检视其中的区别。这个实现中指定了 `Item` 的类型为 `u32`: +关联类型看起来有点像泛型:后者允许定义一个函数时,暂不指定其可以处理的类型。为了体现这两者的区别,请看下面的例子。 +这个例子为 `Counter` 结构体实现了 `Iterator` trait,其中指定 `Item` 的类型为 `u32`: 文件名:src/lib.rs @@ -30,7 +31,7 @@ {{#rustdoc_include ../listings/ch19-advanced-features/no-listing-22-iterator-on-counter/src/lib.rs:ch19}} ``` -这个语法类似于泛型。那么为什么 `Iterator` trait 不像示例 19-13 那样定义呢? +这个语法类似于泛型。那么为什么 `Iterator` trait 不像下面示例 19-13 那样,使用泛型来定义呢? ```rust,noplayground {{#rustdoc_include ../listings/ch19-advanced-features/listing-19-13/src/lib.rs}} @@ -40,9 +41,9 @@ 区别在于当如示例 19-13 那样使用泛型时,则不得不在每一个实现中标注类型。这是因为我们也可以实现为 `Iterator for Counter`,或任何其他类型,这样就可以有多个 `Counter` 的 `Iterator` 的实现。换句话说,当 trait 有泛型参数时,可以多次实现这个 trait,每次需改变泛型参数的具体类型。接着当使用 `Counter` 的 `next` 方法时,必须提供类型注解来表明希望使用 `Iterator` 的哪一个实现。 -通过关联类型,则无需标注类型,因为不能多次实现这个 trait。对于示例 19-12 使用关联类型的定义,我们只能选择一次 `Item` 会是什么类型,因为只能有一个 `impl Iterator for Counter`。当调用 `Counter` 的 `next` 时不必每次指定我们需要 `u32` 值的迭代器。 +有了关联类型,在实现时就无需标注类型,因为不能多次实现这个 trait。对于示例 19-12 使用关联类型的定义,我们只能选择一次 `Item` 会是什么类型,因为只能有一个 `impl Iterator for Counter`。当调用 `Counter` 的 `next` 时不必每次指定我们需要 `u32` 值的迭代器。 -关联类型也会成为 trait 契约的一部分:trait 的实现必须提供一个类型来替代关联类型占位符。关联类型通常有一个描述类型用途的名字,并且在 API 文档中为关联类型编写文档是一个最佳实践。 +关联类型也会成为 trait 契约的一部分:trait 的实现必须提供一个类型来替代关联类型占位符。关联类型通常以它的用途来命名,并且我们最好在 API 文档中为关联类型编写文档。 ### 默认泛型类型参数和运算符重载