使用TcpConnectionNew时未满足`(): futures::Future`的特性限制

11

我正在尝试使用Tokio库在Rust中编写一个简单的TCP客户端。我的代码与这个例子非常接近,只是不包含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 `()`

我觉得很奇怪,因为根据文档,它应该被实现了。

我正在使用:

  • Rust 1.19.0
  • futures 0.1.16
  • tokio-core 0.1.10
  • tokio-io 0.1.3

我漏掉了什么吗?

2个回答

14

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), 并且具有与起始闭包相匹配的错误类型 (Error = Self::Error)。

你的闭包返回什么? ()。为什么?因为你在行末放了一个分号 (;)。 () 没有实现特征IntoFuture, 这由错误消息的一部分 "on the impl of futures::IntoFuture for ()" 表示:

impl<F: Future> IntoFuture for F {
    type Future = F;
    type Item = F::Item;
    type Error = F::Error;
}

去掉分号后,由io::write_all返回的Future将返回到and_then并使程序编译。

一般来说,Futures通过组合自身为 Futures 的较小组件来工作。所有这些都共同工作以构建一个基本上是状态机的单个大的 Future。需要牢记这一点,因为在使用此类组合器时几乎总是需要返回一个 Future。


10
很遗憾,这里的答案非常具体,但是这种问题会出现在任何搜索中,例如:
“trait futures::Future未为()实现”
这种错误的典型场景为:
foo.then(|stream| {
    // ... Do random things here
    final_statement();
});

这会导致错误,因为大多数扩展函数要求返回类型实现IntoFuture。然而,()没有实现IntoFuture,通过以;终止块,隐式返回类型是()
然而,OptionResult都实现了IntoFuture
不要仅仅随意删除分号,希望这样做会让你的代码编译。考虑:
应该返回可以使用IntoFuture转换为Future的内容。
如果您没有特定的承诺要返回,请考虑从回调中返回Ok(())来简单地表示“完成”。
foo.then(|stream| {
    // ... Do random things here
    final_statement();
    return Ok(()); // <-- Result(()) implements `IntoFuture`.
});

需要特别说明的是,我使用显式的返回语句来终止这个代码块;这是有意为之的。这是“可以省略分号以隐式返回对象”的人机工程学典型例子,它实际上会带来明显的负面影响;如果使用Ok(());来终止代码块,将会继续出现相同的错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接