我正在尝试使用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它应该被实现。
我正在使用
我错过了什么?
答案 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;
()
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(());
终止块将继续失败并出现相同的错误。