使用TcpConnectionNew时,不满足特征绑定`():futures :: Future`

时间:2017-10-07 21:38:36

标签: tcp rust rust-tokio

我正在尝试使用Tokio crate在Rust中编写一个简单的TCP客户端。我的代码非常接近this example减去TLS:

extern crate futures;
extern crate tokio_core;
extern crate tokio_io;

use futures::Future;
use tokio_core::net::TcpStream;
use tokio_core::reactor::Core;
use tokio_io::io;

fn main() {
    let mut core = Core::new().unwrap();
    let handle = core.handle();

    let connection = TcpStream::connect(&"127.0.0.1:8080".parse().unwrap(), &handle);

    let server = connection.and_then(|stream| {
        io::write_all(stream, b"hello");
    });

    core.run(server).unwrap();
}

但是,编译失败并显示错误:

error[E0277]: the trait bound `(): futures::Future` is not satisfied
  --> src/main.rs:16:29
   |
16 |     let server = connection.and_then(|stream| {
   |                             ^^^^^^^^ the trait `futures::Future` is not implemented for `()`
   |
   = note: required because of the requirements on the impl of `futures::IntoFuture` for `()`

error[E0277]: the trait bound `(): futures::Future` is not satisfied
  --> src/main.rs:20:10
   |
20 |     core.run(server).unwrap();
   |          ^^^ the trait `futures::Future` is not implemented for `()`
   |
   = note: required because of the requirements on the impl of `futures::IntoFuture` for `()`

我发现它很奇怪,因为根据the documentation它应该被实现。

我正在使用

  • Rust 1.19.0
  • 期货0.1.16
  • tokio-core 0.1.10
  • tokio-io 0.1.3

我错过了什么?

2 个答案:

答案 0 :(得分:9)

TL; DR:在io::write_all之后删除分号。

查看and_then的定义:

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, 

闭包(F)必须返回一些类型(B),它可以转换为一个带有与起始闭包匹配的错误类型的未来(B: IntoFuture){{{ 1}})。

你的关闭返回什么? Error = Self::Error。这是为什么?因为您已在行的末尾放置了分号(())。 ;没有implement the trait IntoFuture()futures::IntoFuture&#34;

的错误消息部分&#34;表示()
impl<F: Future> IntoFuture for F {
    type Future = F;
    type Item = F::Item;
    type Error = F::Error;
}

删除分号将导致Future返回的io::write_all返回and_then,程序将编译。

一般而言,期货通过将较小的组成部分组合在一起而起作用。所有这些共同构建了一个基本上是状态机的单一大型未来。记住这一点很好,因为在使用这种组合器时,你几乎总是需要回归未来。

答案 1 :(得分:4)

不幸的是,这里的答案非常具体,但问题出现在任何类型的搜索中:

  

futures::Future

未实现特征()

此类错误的典型情况是:

foo.then(|stream| {
    // ... Do random things here
    final_statement();
});

这会导致错误,因为大多数extension functions都需要返回类型来实现IntoFuture。但是,()未实现IntoFuture,并且通过使用;终止块,隐式返回类型为()

但是,为Option and Result实施了IntoFuture

不要只是随意删除分号,希望这会以某种方式神奇地使你的代码编译,考虑:

您应该使用Future返回可以转换为IntoFuture的内容。

如果您没有具体承诺要退回,请考虑返回Ok(())从回调中简单地说“这已经完成”:

foo.then(|stream| {
    // ... Do random things here
    final_statement();
    return Ok(()); // <-- Result(()) implements `IntoFuture`.
});

特别注意我使用显式return语句终止此块;这是故意的。这是“可以省略分号以隐含返回对象”的人体工程学如何明显有害的典型示例;使用Ok(());终止块将继续失败并出现相同的错误。