I am trying to write a simple TCP client in Rust using Tokio crate. My code is pretty close to this example minus the 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();
}
However, compilation fails with the error:
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 `()`
I find it strange because according to the documentation it should be implemented.
I'm using
What am I missing?
Unfortunately the answer here is quite specific, but the question turns up for any kind of search for:
the trait
futures::Future
is not implemented for()
A typical scenario for this kind of error is:
foo.then(|stream| {
// ... Do random things here
final_statement();
});
This causes an error because the majority of the extension functions require the return type to implement IntoFuture
. However, ()
does not implement IntoFuture
, and by terminating the block with a ;
the implicit return type is ()
.
However, IntoFuture
is implemented for Option
and Result
.
Rather than just randomly removing semicolons vaguely in the hope this will somehow magically make your code compile, consider:
You should be returning something that can be converted into a Future
using IntoFuture
.
If you don't have a specific promise that you're returning, consider returning Ok(())
to say simply 'this is done' from your callback:
foo.then(|stream| {
// ... Do random things here
final_statement();
return Ok(()); // <-- Result(()) implements `IntoFuture`.
});
Note specifically I terminate this block with an explicit return statement; this is deliberate. This is a typical example of how the ergonomics of 'can omit semicolon to implicitly return object' is tangibly harmful; terminating the block with Ok(());
will continue to fail with the same error.
TL;DR: remove the semicolon after io::write_all
.
Review the definition of 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,
The closure (F
) has to return some type (B
) that can be converted into a future (B: IntoFuture
) with an error type that matches the starting closure (Error = Self::Error
).
What does your closure return? ()
. Why is that? Because you've placed a semicolon (;
) at the end of your line. ()
does not implement the trait IntoFuture
, which is indicated by the error message part "on the impl of futures::IntoFuture
for ()
":
impl<F: Future> IntoFuture for F {
type Future = F;
type Item = F::Item;
type Error = F::Error;
}
Removing the semicolon will cause the Future
returned by io::write_all
to be returned back to and_then
and the program will compile.
In general, futures work by combining together smaller components which are themselves futures. All of this works together to build a single large future which is essentially a state machine. It's good to keep this in mind, as you will almost always need to return a future when using such combinators.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With