How can i call a dyn function stored within a Box?

51 Views Asked by At

I have this snippet:

use std::sync::{Arc, Mutex};

pub struct TaskGroup
{
    task_group: Arc<Mutex<Box<dyn Fn() -> dyn Iterator<Item=usize>>>>,
}

impl TaskGroup
{
    fn foo(&self)
    {
        for task in self
                .task_group
                .lock()
                .unwrap()()
        {}
    }
}

Which returns:

error[E0618]: expected function, found `MutexGuard<'_, Box<(dyn Fn() -> (dyn Iterator<Item = task::TaskHandle> + 'static) + 'static)>>`
  --> crates/thread_pool/src/task.rs:60:25
   |
60 |               for task in self // task
   |  _________________________^
61 | |                 .post_reqs // RwLock
62 | |                 .read() // handle
63 | |                 .unwrap() // Ref to TaskGroup
64 | |                 .task_group // TaskGroup
65 | |                 .lock()// Mutex lock
66 | |                 .unwrap()()
   | |_________________________^ this trait object returns an unsized value `(dyn Iterator<Item = task::TaskHandle> + 'static)`, so it cannot be called

So what is the correct way to call the function in the box and get the iterator?

1

There are 1 best solutions below

0
vallentin On BEST ANSWER

The issue is the same as why the following doesn't work:

fn f() -> dyn Iterator<Item = usize> {
    0..10
}

You're attempting to return something that doesn't have a size known at compile-time. If it was a regular fn, then you could replace dyn with impl (or return position impl trait) and everything would work fine. However, since you're dealing with closures, then things get a bit more complicated. You need to box it.

use std::sync::{Arc, Mutex};

let f: Arc<Mutex<Box<dyn Fn() -> Box<dyn Iterator<Item = usize>>>>> =
    Arc::new(Mutex::new(Box::new(|| Box::new((0..10).into_iter()))));

let mut guard = f.lock().unwrap();
let f = guard.as_mut();

for x in f() {
    println!("{}", x);
}

Remember to store the guard returned by .lock(). Otherwise the compiler will complain about a temporary being freed while still in use.