最后的一步
现在我们的 future 确实是可以工作了,但这并没有给你展示出 future 的威力。所以我们来写一个超级好用的 future 和上面的 future 串联起来。它可以给可以执行加一运算的类型执行加一操作。下面是我们的例子 MyFuture
。
struct AddOneFuture<T>(T);
impl<T> Future for AddOneFuture<T>
where
T: Future,
T::Output: std::ops::Add<i32, Output = i32>,
{
type Output = i32;
fn poll(&mut self, ctx: &Context) -> Poll<Self::Output> {
match self.0.poll(ctx) {
Poll::Ready(count) => Poll::Ready(count + 1),
Poll::Pending => Poll::Pending,
}
}
}
它看起来很复杂,但实际上很简单。我们来一行行的看。
-
struct AddOneFuture<T>(T)
这是基于泛型来定义新类型的一种方式的例子。它使我们可以包装其它的结构体,并添加新的行为。 -
impl<T> Future for AddOneFuture<T>
是泛型 trait 的实现。 -
T: Future
确保所有AddOneFuture
包装的类型都实现了 future trait。 -
T::Item: std::ops::Add<i32, Output=i32>
确保Poll::Ready(value)
代表的值可以进行加法运算。
剩下的代码就比较好理解了,它通过 self.0.poll
轮询内部的 future,将 context
透传给它。根据轮询的结果返回 Poll::Pending
或者 Poll::Ready(count+1)
。
我们可以更新main
函数来运行我们的 future。
fn main() {
let my_future = MyFuture::default();
println!("Output: {}", run(AddOneFuture(my_future)));
}
现在我们开始看到 futures 是如何把异步行为串联起来的了。只需要简单的几步就可以构建串联函数(combinators) 来大大的增强 future 的能力。