Search code examples
genericsrustfunction-pointerstraits

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


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?


Solution

  • 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.