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