问题
I am learning Tokio. I read Getting asynchronous from the official docs, but the source code from the Chaining computations section cannot be compiled under the latest Rust version (Rust 2018, v1.31):
extern crate tokio;
extern crate bytes;
#[macro_use]
extern crate futures;
use tokio::io::AsyncWrite;
use tokio::net::{TcpStream, tcp::ConnectFuture};
use bytes::{Bytes, Buf};
use futures::{Future, Async, Poll};
use std::io::{self, Cursor};
// HelloWorld has two states, namely waiting to connect to the socket
// and already connected to the socket
enum HelloWorld {
Connecting(ConnectFuture),
Connected(TcpStream, Cursor<Bytes>),
}
impl Future for HelloWorld {
type Item = ();
type Error = io::Error;
fn poll(&mut self) -> Poll<(), io::Error> {
use self::HelloWorld::*;
loop {
let socket = match *self {
Connecting(ref mut f) => {
try_ready!(f.poll())
}
Connected(ref mut socket, ref mut data) => {
// Keep trying to write the buffer to the socket as long as the
// buffer has more bytes it available for consumption
while data.has_remaining() {
try_ready!(socket.write_buf(data));
}
return Ok(Async::Ready(()));
}
};
let data = Cursor::new(Bytes::from_static(b"hello world"));
*self = Connected(socket, data);
}
}
}
fn main() {
let addr = "127.0.0.1:1234".parse().unwrap();
let connect_future = TcpStream::connect(&addr);
let hello_world = HelloWorld::Connecting(connect_future);
// Run it
tokio::run(hello_world)
}
The compiler outputs error messages:
error[E0271]: type mismatch resolving `<HelloWorld as futures::Future>::Error == ()`
--> src\main.rs:54:5
|
54 | tokio::run(hello_world)
| ^^^^^^^^^^ expected struct `std::io::Error`, found ()
|
= note: expected type `std::io::Error`
found type `()`
= note: required by `tokio::run`
Is the problem caused by the version of my Rust compiler? How do I fix it?
回答1:
Tokio::run has the following signature:
pub fn run<F>(future: F)
where
F: Future<Item = (), Error = ()> + Send + 'static,
which means that it accepts a Future
which accepts a ()
as Item
and has ()
as the error type.
On the other hand, your HelloWorld
impl has
type Item = ();
type Error = io::Error;
which means they are not compatible, you have to convert the io::Error
to ()
somehow.
I would suggest using map_err
tokio::run(hello_world.map_err(|e| Err(e).unwrap()))
to handle the error in case something bad happens. You could of course make better error handling, but this will work.
Interestingly enough, I have JavaScript disabled in my browser and therefore I see the comments in the Rustdoc on the webpage:
fn main() {
let addr = "127.0.0.1:1234".parse().unwrap();
let connect_future = TcpStream::connect(&addr);
let hello_world = HelloWorld::Connecting(connect_future);
# let hello_world = futures::future::ok::<(), ()>(());
// Run it
tokio::run(hello_world)
}
The #
means that Rustdoc should not print that line, but should execute it while testing. I think this is a mistake/oversight and there is also an open issue and a fix pending. PR has been merged, webpage has been updated.
来源:https://stackoverflow.com/questions/53818465/the-example-from-the-chaining-computations-section-of-the-tokio-docs-does-not