Tokio 文档 "chaining computations" 部分的示例无法编译:"expected struct `std::io::Error`, found ()"

The example from the "chaining computations" section of the Tokio docs does not compile: "expected struct `std::io::Error`, found ()"

我正在从官方文档中学习Tokio. I read Getting asynchronous,但是Chaining computations部分的源代码无法在最新的Rust版本下编译(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)
}

编译器输出错误信息:

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`

是不是我的Rust编译器版本问题?我该如何解决?

Tokio::run 具有以下签名:

pub fn run<F>(future: F)
where
    F: Future<Item = (), Error = ()> + Send + 'static, 

这意味着它接受一个 Future 接受一个 () 作为 Item 并且有 () 作为错误类型。

另一方面,您的 HelloWorld impl 有

type Item = ();
type Error = io::Error;

这意味着它们不兼容,您必须以某种方式将 io::Error 转换为 ()

我建议使用 map_err

tokio::run(hello_world.map_err(|e| Err(e).unwrap()))

处理错误以防万一发生不好的事情。您当然可以进行更好的错误处理,但这会起作用。


有趣的是,我在浏览器中禁用了 JavaScript,因此我在网页上的 Rustdoc 中看到了评论:

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)
}

# 表示 Rustdoc 不应打印该行,但应在测试时执行它。 我觉得这是一个mistake/oversight,还有一个open issue and a fix pendingPR已合并,网页已更新。