问题
I'm trying to understand asynchronous I/O in Rust. The following code is based on a snippet from Katharina Fey's Jan 2019 talk which works for me:
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);
}
Before finding that code, I attempted to figure it out from the read_until documentation.
How do I interpret the signature of read_until
to use it in a code sample like the one above?
pub fn read_until<A>(a: A, byte: u8, buf: Vec<u8>) -> ReadUntil<A>
where
A: AsyncRead + BufRead,
Specifically, how can I know from reading the documentation, what are the parameters passed into the and_then
closure and the expected result?
回答1:
Parameters to and_then
Unfortunately the standard layout of the Rust documentation makes futures quite hard to follow.
Starting from the read_until documentation you linked, I can see that it returns ReadUntil<A>
. I'll click on that to go to the ReadUntil documentation.
This return value is described as:
A future which can be used to easily read the contents of a stream into a vector until the delimiter is reached.
I would expect it to implement the Future
trait — and I can see that it does. I would also assume that the Item
that the future resolves to is some sort of vector, but I don't know exactly what, so I keep digging:
- First I look under "Trait implementations" and find
impl<A> Future for ReadUntil<A>
- I click the
[+]
expander
Finally I see the associated type Item = (A, Vec<u8>)
. This means it's a Future
that's going to return a pair of values: the A
, so it is presumably giving me back the original reader
that I passed in, plus a vector of bytes.
When the future resolves to this tuple, I want to attach some additional processing with and_then
. This is part of the Future
trait, so I can scroll down further to find that function.
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,
The function and_then
is documented as taking two parameters, but self
is passed implicitly by the compiler when using dot syntax to chain functions, which tells us that we can write read_until(A, '\n', buffer).and_then(...)
. The second parameter in the documentation, f: F
, becomes the first argument passed to and_then
in our code.
I can see that f
is a closure because the type F
is shown as FnOnce(Self::Item) -> B
(which if I click through links to the Rust book closure chapter.
The closure f
that is passed in takes Self::Item
as the parameter. I just found out that Item
is (A, Vec<u8>)
, so I expect to write something like .and_then(|(reader, buffer)| { /* ... /* })
AsyncRead
+ BufRead
This is putting constraints on what type of reader can be read from. The created BufReader implements BufRead.
Helpfully, Tokio provides an implementation of AsyncRead for BufReader so we don't have to worry about it, we can just go ahead and use the BufReader
.
来源:https://stackoverflow.com/questions/56402818/how-do-i-interpret-the-signature-of-read-until-and-what-is-asyncread-bufread-i