How to pass a Future as a function argument?

3.3k Views Asked by At

I am used to Scala's Future type where you wrap whatever object you're returning in Future[..] to designate it as such.

My Rust function hello returns Query and I don't seem able to pass that result as an argument with type Future<Output = Query>. Why not and how should I type this better?

The failure occurs when I try to pass the future as an argument:

use std::future::Future;

struct Person;
struct DatabaseError;

type Query = Result<Vec<Person>, DatabaseError>;

async fn hello_future(future: &dyn Future<Output = Query>) -> bool {
    future.await.is_ok()
}

async fn hello() -> Query {
    unimplemented!()
}

async fn example() {
    let f = hello();
    hello_future(&f);
}

fn main() {}

Which fails to compile with the error:

error[E0277]: `&dyn Future<Output = Result<Vec<Person>, DatabaseError>>` is not a future
 --> src/main.rs:9:5
  |
9 |     future.await.is_ok()
  |     ^^^^^^^^^^^^ `&dyn Future<Output = Result<Vec<Person>, DatabaseError>>` is not a future
  |
  = help: the trait `Future` is not implemented for `&dyn Future<Output = Result<Vec<Person>, DatabaseError>>`
  = note: required by `poll`
2

There are 2 best solutions below

0
On BEST ANSWER

async functions desugar to returning an opaque value that implements the Future trait. This means that you can accept a generic type that implements that trait. The most succinct syntax is impl Trait, but you could also introduce a named generic parameter:

async fn hello_future(future: impl Future<Output = Query>) -> bool {
    future.await.is_ok()
}

async fn example() {
    let f = hello();
    hello_future(f);
}

See also:

0
On

You can also use Pin<Box<dyn Future<Output = Query>>> as parameter:

async fn hello_future(future: Pin<Box<dyn Future<Output = Query>>>) -> bool {
    future.await.is_ok()
}
...
async fn example() {
    let f: impl Future<Output = Result<Vec<Person>, DatabaseError>> = hello();
    hello_future(Box::pin(f));
}

The difference is that impl Future is compile-time dispatch. Compiler generates executable code for each per-type instantiation of hello_future. And Pin<Box<...>> is runtime dispatch. Only one copy of the executable binary code for hello_future is generated.