I write a test code which is a modified version of https://github.com/tokio-rs/tokio-line/blob/master/multiplexed/examples/echo_client_server.rs
Just few lines (see below) are replaced:
core.run(
line::Client::connect(&addr, &handle)
.map(Box::new)
.and_then(|client| {
let init = future::ok(client).boxed();
(0..10).into_iter().fold(init, move |f, i| {
f.and_then(move |client| {
client.call(format!("iter {}", i))
.map(move |response| {
println!("-> {:?}", response);
client
})
})
.boxed()
})
})
).unwrap();
What I want is send requests one by one after previous response back.
But this can not compiled,
error[E0277]: the trait bound `futures::Future<Error=std::io::Error, Item=std::string::String>: std::marker::Send` is not satisfied in `futures::AndThen<Box<futures::Future<Error=std::io::Error, Item=Box<line::Client>> + std::marker::Send>, futures::Map<Box<futures::Future<Error=std::io::Error, Item=std::string::String>>, [closure@examples\echo_client_server.rs:46:34: 49:30 client:_]>, [closure@examples\echo_client_server.rs:44:32: 50:22 i:_]>`
--> examples\echo_client_server.rs:51:22
|
51 | .boxed()
| ^^^^^ within `futures::AndThen<Box<futures::Future<Error=std::io::Error, Item=Box<line::Client>> + std::marker::Send>, futures::Map<Box<futures::Future<Error=std::io::Error, Item=std::string::String>>, [closure@examples\echo_client_server.rs:46:34: 49:30 client:_]>, [closure@examples\echo_client_server.rs:44:32: 50:22 i:_]>`, the trait `std::marker::Send` is not implemented for `futures::Future<Error=std::io::Error, Item=std::string::String>`
|
= note: `futures::Future<Error=std::io::Error, Item=std::string::String>` cannot be sent between threads safely
= note: required because it appears within the type `Box<futures::Future<Error=std::io::Error, Item=std::string::String>>`
= note: required because it appears within the type `futures::Map<Box<futures::Future<Error=std::io::Error, Item=std::string::String>>, [closure@examples\echo_client_server.rs:46:34: 49:30 client:_]>`
= note: required because it appears within the type `futures::future::chain::Chain<Box<futures::Future<Error=std::io::Error, Item=Box<line::Client>> + std::marker::Send>, futures::Map<Box<futures::Future<Error=std::io::Error, Item=std::string::String>>, [closure@examples\echo_client_server.rs:46:34: 49:30 client:_]>, [closure@examples\echo_client_server.rs:44:32: 50:22 i:_]>`
= note: required because it appears within the type `futures::AndThen<Box<futures::Future<Error=std::io::Error, Item=Box<line::Client>> + std::marker::Send>, futures::Map<Box<futures::Future<Error=std::io::Error, Item=std::string::String>>, [closure@examples\echo_client_server.rs:46:34: 49:30 client:_]>, [closure@examples\echo_client_server.rs:44:32: 50:22 i:_]>`
It am very puzzled by this, and have no idea how to fix it. Could anyone here give my some help?
I can get it to typecheck by switching from .boxed() to Box::new() (see this issue) and explicitly annotating the intended type for init:
core.run(
line::Client::connect(&addr, &handle)
.map(Box::new)
.and_then(|client| {
let init = Box::new(::futures::future::ok(client))
as Box<Future<Item=Box<line::Client>,Error=::std::io::Error>>;
(0..10).into_iter().fold(init, move |f, i| {
Box::new(f.and_then(move |client| {
client.call(format!("iter {}", i))
.map(move |response| {
println!("-> {:?}", response);
client
})
}))
})
})
).unwrap();
Note that the future you are constructing here will have size proportional to your iterator, which in this case has ten elements. A better approach might be to use loop_fn(), which would allow the loop to lazily unroll as it executes, maintaining a constant size independent of the number of elements in the iterator.
I believe @dwrensha was spot on, so closing. Thanks for the report though!
@dwrensha thank you very much. It is a very clear explaination.
The whole as Box<Future<Item=Box<line::Client>,Error=::std::io::Error>> bit is terrifying, and I say this as somebody who thinks Rust is basically an easy and fun language, not a hard one. I would really need better error messages to be comfortable using tokio at work. Could the compiler help here in any way?
Most helpful comment
The whole
as Box<Future<Item=Box<line::Client>,Error=::std::io::Error>>bit is terrifying, and I say this as somebody who thinks Rust is basically an easy and fun language, not a hard one. I would really need better error messages to be comfortable usingtokioat work. Could the compiler help here in any way?