Reputation: 1108
I need a closure that captures by-value and is called at most once, but I cannot have the function using the closure monomorphise on every passed closure, because the closures and functions are mutually recursive and the monomorphisation phase fails. I tried something like:
fn closure_user(closure: Box<FnOnce(usize) -> bool>) -> bool {
closure(3)
}
fn main() {
let big_data = vec![1, 2, 3, 4];
closure_user(Box::new(|x| {
let _ = big_data.into_iter();
false
}));
}
error[E0161]: cannot move a value of type dyn std::ops::FnOnce(usize) -> bool: the size of dyn std::ops::FnOnce(usize) -> bool cannot be statically determined
--> src/main.rs:2:5
|
2 | closure(3)
| ^^^^^^^
The unboxed version is:
fn closure_user<F>(closure: F) -> bool
where
F: FnOnce(usize) -> bool,
{
closure(42)
}
fn main() {
let big_data = vec![1, 2, 3, 4];
closure_user(|x| {
let _ = big_data.into_iter();
false
});
}
It seems that it is impossible to box and unbox the closure as a FnOnce
trait object. Is there any way to have boxed (no type parameter) and by-move (one call only) closures?
Upvotes: 1
Views: 769
Reputation: 29981
It is possible, but for now you have to do it through the unstable std::thunk::Thunk
:
use std::thunk::{Invoke, Thunk};
fn closure_user(closure: Thunk<usize, bool>) -> bool {
closure.invoke(3)
}
fn main() {
let big_data = vec![1, 2, 3, 4];
closure_user(Thunk::with_arg(|x| {
let _ = big_data.into_iter();
false
}));
}
This is due to limitations on the current type system - it's not possible to move out from a trait object - and should be addressed soon. For more information, see the blog post Purging Proc.
Upvotes: 2
Reputation: 431789
As of Rust 1.35, this is now possible using your original syntax:
fn closure_user(closure: Box<dyn FnOnce(usize) -> bool>) -> bool {
closure(3)
}
fn main() {
let big_data = vec![1, 2, 3, 4];
closure_user(Box::new(|x| {
let _ = big_data.into_iter();
false
}));
}
Upvotes: 3