While the code you provided compiles, I was trying to use work from the global scope as defined in my first code block. This is still failing to compile:
async fn work() {}
impl<C: Fn() -> T, T: Future> AnotherStruct<C, T> {
fn new() -> Self {
// perhaps the compiler needs a hint here?
let work: C = work;
Self { task: work }
}
}
fn third_test() {
let w = AnotherStruct::new();
}
The issue is that you're asking the user for a type T and then promising to return a future of that type T. But work() only returns a single type of future, which isn't necessarily of the type T that the user asked for. One way around this problem is something like this:
use std::future::Future;
struct MyStruct<T> {
task: fn() -> T,
}
async fn work() {}
impl MyStruct<()> {
fn new() -> MyStruct<impl Future<Output=()>> {
MyStruct { task: work }
}
}
fn second_test() {
let x = MyStruct::new();
}
@2e71828, is the impl MyStruct<()> a typo or do I need to do some more reading? I guess the latter since your code indeed works. I would have thought the implementation block would have been something like:
impl MyStruct<()> is valid and can sometimes be used to avoid type inference errors. It means you provide an implementation for a concrete value of generic argument: MyStruct::new will only be available for MyStruct<()>, not any MyStruct<T>. However, I don't see how this approach would be useful here.
Because the returned Future is an unnameable type, I needed a nameable placeholder type for the impl block to make the type inference work. You can use any type you like here, as no MyStruct<()> will ever be created.
In effect, I'm using it to define some free functions in the MyStruct namespace. It's roughly equivalent to this:
fn new_work() -> MyStruct<impl Future<Output=()>> {
MyStruct { task: work }
}
fn second_test() {
let x = new_work();
}
For sure, one's life is easiest if you put everything behind a box, but I want to understand how to solve this problem without having to rely on allocation.
The issue here is that new is a generic implementation block which is supposed to be generic over T and C. However my new function is the opposite, it only works for the specific closure C and future T created by the closure and async block.
So in your solution, @2e71828, MyStruct::new() is basically shorthand for MyStruct::<()>::new()