I'm learning Rust and getting really frustrated trying to use async-tungstenite to make a program which simultaneously:
- Receives and handles messages from a server that arrive via WebSocket.
- Monitor the local filesystem and send messages to the server when local files change.
The client example in async-tungstenite demonstrates how to use StreamExt::for_each with a Source
to asynchronously receive and handle incoming messages. It takes a closure which returns a future. I've been trying all day to get this working, but running into issues either constructing the closure or a function which returns the closure to be passed to for_each
.
The following MVCE illustrates the problem I'm running into right now. It's probably something I misunderstand about Rust, so I could use help understanding this properly. What I'd like to know how to do is write a function which returns a closure which returns a future. I'm trying to write the closure such that it delegates to an asynchronous function. The compiler doesn't seem to get it that the asynchronous function, which returns a future, is not compatible with what the closure is expected to return, also a future, with the same output. Is this a shortcoming of Rust, or bad syntax, or a misunderstanding of mine on how to implement this in Rust?
async fn foo() {
println!("foo");
}
// // This is preferred, but currently results in this error:
// //
// // error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
// //
// fn make_foo_closure() -> impl FnMut() -> impl futures::Future<Output = ()> {
// println!("make_foo_closure");
// || foo()
// }
fn make_foo_closure<'a, Fut>() -> impl FnMut() -> Fut + 'a where
Fut: futures::Future<Output = ()>
{
println!("make_foo_closure");
|| foo()
}
fn main() {
println!("Making a closure which calls foo");
let foo_closure = make_foo_closure();
println!("Calling the closure");
futures::executor::block_on(
foo_closure()
);
println!("Done");
}
Errors:
Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
--> src/main.rs:18:8
|
1 | async fn foo() {
| - the `Output` of this `async fn`'s found opaque type
...
14 | fn make_foo_closure<'a, Fut>() -> impl FnMut() -> Fut + 'a where
| --- this type parameter
...
18 | || foo()
| ^^^^^ expected type parameter `Fut`, found opaque type
|
= note: expected type parameter `Fut`
found opaque type `impl core::future::future::Future`
= help: type parameters must be constrained to match other types
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
error[E0282]: type annotations needed
--> src/main.rs:23:23
|
23 | let foo_closure = make_foo_closure();
| ----------- ^^^^^^^^^^^^^^^^ cannot infer type for type parameter `Fut` declared on the function `make_foo_closure`
| |
| consider giving `foo_closure` a type
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0282, E0308.
For more information about an error, try `rustc --explain E0282`.
error: could not compile `playground`.
To learn more, run the command again with --verbose.