「这是我参与11月更文挑战的第 6 天,活动详情查看:2021最后一次更文挑战」
step 1
Map类型有一个极其灵活的类型定义,一个没有边界的泛型。新方法也没有边界,但它只在std::iter中可用。
让我们把这个应用到我们的Connector上:
1 | rust复制代码struct Connector<I, F> { |
step 2
一般来说,std::iter类型在其内部迭代器上调用next并很容易改变其行为。其中许多类型,如Take::next,都是用非常简单的代码完成的。
标准库还告诉我们,impl block 是我们应该施加 trait bounds 的地方,因为这是严格意义上的必要的地方。请注意,迭代器类型有一个相关的类型叫做Item。语法 <Item = Something>
将其与通用类型区分开来。
这取代了我们简单地从Vec中抓取项目的旧代码。这将适用于任何能够创建迭代器的类型,其中Item是Point:
1 | rust复制代码impl<Id, I, F> Iterator for Connector<I, F> |
step 3
迭代器有产生其他迭代器的方法。如果一个例子还不够,可以在 Iterator trait
中还可以找到几十个其他的例子。
首先,我们需要改变Connect trait,因为它的方法会返回一个Connector,这一点已经被改变了。我们重写了Connector以使其更加灵活,所以让我们对Connect做同样的事情。我们将继续采用将 trait bounds 从定义中移出并移入实现的方式:
1 | rust复制代码trait Connect<I, F> { |
我们不能给Iterator添加方法,它不是我们代码的一部分。但是我们可以使用一个非常有用的技巧:我们将为每个实现了Iterator的类型实现我们的Connect方法。
1 | rust复制代码impl<I, Id, F> Connect<Id, F> for I |
这被称为自动实现。标准库经常使用它们。一个众所周知的例子是,为一个类型实现Display会给它一个ToString的自动实现。
Fn trait bound 也被删除了,因为Connect和Connector不再需要它了。由于选择性的灵活性,我们优雅地使我们的代码更简单,更强大。让我们看看我们的新代码的运行情况:
1 | rust复制代码fn main() { |
我们的代码比我们为Vec手动实现Connect时做的要多得多,但我们使用的行数却完全相同。想象一下,为std::collection中的每个类型手动实现Connect所需要的代码量。由于泛型的复杂性,我们只用一个代码块就能得到同样的东西,并且让编译器来填补空白。
本文转载自: 掘金