Gabriel Machado
Gabriel Machado

Reputation: 493

How to store a future without boxing it

I want to do the following

struct Stored<F: Future<Output = ()>> {
    f: Option<F>,
}

impl<F: Future<Output = ()>> Stored<F> {
    fn store(&mut self, f: F) {
        let f = async {};
        self.f = Some(f);
    }
}

But it gives me the error:

expected type parameter `F`
      found opaque type `impl futures::Future<Output = ()>`
type parameters must be constrained to match other types

I could solve it boxing the future, but if the method store was the only place I stored this future, there would be no need to do that, because all the future blocks would be always the same type. How could I do it?

Upvotes: 1

Views: 574

Answers (1)

cdhowie
cdhowie

Reputation: 168958

This doesn't work because F is a generic type provided from outside of the Stored type, but the actual type of the future is an unnamed type provided from within the store associated function (created by async {}). There is no possible way that F can be specified to be the correct type.

The way this is usually handled is to create a dedicated, nameable type implementing Future. In this trivial case, that could be std::future::Ready<()>:

struct Stored {
    f: Option<std::future::Ready<()>>,
}

impl Stored {
    fn store(&mut self) {
        self.f = Some(std::future::ready(()));
    }
}

If the type of the future actually does come from outside of the type, then you just need to adjust your code to use f directly instead of discarding it and using async {}:

use std::future::Future;

struct Stored<F> {
    f: Option<F>,
}

impl<F: Future> Stored<F> {
    fn store(&mut self, f: F) {
        self.f = Some(f);
    }
}

Upvotes: 2

Related Questions