如何解释 read_until 的签名以及 Tokio 中的 AsyncRead + BufRead 是什么?

How do I interpret the signature of read_until and what is AsyncRead + BufRead in Tokio?

我正在尝试理解 Rust 中的异步 I/O。以下代码基于 Katharina Fey 的片段 Jan 2019 talk 对我有用:

use futures::future::Future;
use std::io::BufReader;
use tokio::io::*;

fn main() {
    let reader = BufReader::new(tokio::io::stdin());
    let buffer = Vec::new();

    println!("Type something:");
    let fut = tokio::io::read_until(reader, b'\n', buffer)
        .and_then(move |(stdin, buffer)| {
            tokio::io::stdout()
                .write_all(&buffer)
                .map_err(|e| panic!(e))
        })
        .map_err(|e| panic!(e));

    tokio::run(fut);
}

在找到该代码之前,我试图从 read_until 文档中找出它。

如何解释 read_until 的签名以在上面的代码示例中使用它?

pub fn read_until<A>(a: A, byte: u8, buf: Vec<u8>) -> ReadUntil<A> 
where
    A: AsyncRead + BufRead, 

具体来说,我如何通过阅读文档知道传递给 and_then 闭包的参数和预期结果是什么?

and_then

的参数

不幸的是,Rust 文档的标准布局使得 futures 很难遵循。

read_until documentation you linked, I can see that it returns ReadUntil<A>. I'll click on that to go to the ReadUntil documentation开始。

此 return 值描述为:

A future which can be used to easily read the contents of a stream into a vector until the delimiter is reached.

我希望它能实现 Future 特性——我可以看到它确实如此。我还假设未来解决的 Item 是某种向量,但我不知道到底是什么,所以我继续挖掘:

  1. 首先,我查看 "Trait implementations" 并找到 impl<A> Future for ReadUntil<A>
  2. 我点击 [+] 扩展器

终于看到关联的type Item = (A, Vec<u8>)了。这意味着它是一个 Future 将要 return 一对值:A,所以它可能会返回我传入的原始 reader,加上一个字节向量。

当 future 解析到这个元组时,我想用 and_then 附加一些额外的处理。这是 Future 特征的一部分,因此我可以向下滚动以找到该函数。

fn and_then<F, B>(self, f: F) -> AndThen<Self, B, F>
where
    F: FnOnce(Self::Item) -> B,
    B: IntoFuture<Error = Self::Error>,
    Self: Sized,

函数 and_then 被记录为采用两个参数,但是 self 在使用点语法时被编译器隐式传递给 chain 函数,这告诉我们可以写 read_until(A, '\n', buffer).and_then(...)。文档中的第二个参数 f: F 成为我们代码中传递给 and_then 的第一个参数。

我可以看到 f 是一个闭包,因为类型 F 显示为 FnOnce(Self::Item) -> B(如果我点击指向 Rust book closure chapter 的链接。

传入的闭包fSelf::Item为参数。我刚刚发现 Item(A, Vec<u8>),所以我希望写成 .and_then(|(reader, buffer)| { /* ... /* })

AsyncRead + BufRead

这限制了可以读取 reader 的类型。创建的 BufReader implements BufRead.

有用的是,Tokio 提供了 an implementation of AsyncRead for BufReader 所以我们不必担心,我们可以继续使用 BufReader.