问题
This question is about how to read the Rust documentation and improve my understanding of Rust so as to understand how to address this specific compiler error.
I've read the tokio docs and experimented with many of the examples. In writing my own code, I frequently run into compiler errors that I don't understand and often found I can fix the code, but don't understand why specific syntax is needed.
I reproduced with a very simple example based on tokio's hello world:
use futures::Future;
use tokio::net::TcpStream;
use tokio::prelude::*;
fn main() {
let addr = "127.0.0.1:6142".parse().unwrap();
let client = TcpStream::connect(&addr).and_then(|stream| {
println!("created stream");
// Process stream here.
// Ok(())
});
}
The above code is incorrect, requiring the commented out Ok()
. I know that this is true, but not exactly why. This is perhaps the other half of a prior question How do I interpret the signature of read_until and what is AsyncRead + BufRead in Tokio? -- now I understand closures better, but can't quite parse the docs to understand the expected return value.
When I attempt to compile the incorrect code above, I get the following error:
error[E0277]: the trait bound `(): futures::future::Future` is not satisfied
--> tokio-chat-client/src/main.rs:8:42
|
8 | let client = TcpStream::connect(&addr).and_then(|stream| {
| ^^^^^^^^ the trait `futures::future::Future` is not implemented for `()`
|
= note: required because of the requirements on the impl of `futures::future::IntoFuture` for `()`
There are two parts to my question:
- What is the error message trying to tell me?
- How would I use the docs for and_then to understand the expected return value?
回答1:
The docs for and_then state that:
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,
This means that:
- Your closure must accept an argument of type
Self::Item
and return some typeB
- The type
B
returned by your closure must be convertible into a future. - And if that future returns an error, then that error must have type
Self::Error
.
Moreover, if you look at the doc for IntoFuture, you will see that it is implemented for Result, so it works for Ok(())
, but that it is not implemented for ()
, so it doesn't work if your closure returns nothing.
回答2:
Basically the closure you pass to and_then has the wrong type. It expects:
F: FnOnce(Self::Item) -> B
But you give it a closure of unit type, i.e. returns no value. Hence the error.
That said, the rustc
error message isn't optimal here. It would be much better if it reads:
let client = TcpStream::connect(&addr).and_then(|stream| {
println!("created stream");
// error: mismatched types: expected `IntoFuture` but found `()`
});
The rust-lang project has this ticket to track the progress on said diagnostics issue.
来源:https://stackoverflow.com/questions/57720321/understanding-error-trait-futuresfuturefuture-is-not-implemented-for