I'm trying to do some higher order programming in Rust, but I'm having some difficulty dealing with closures. Here's a code snippet that illustrates one of the problems I'm having:
pub enum Foo {
Bar(Box<FnOnce(i32)>),
}
pub fn app(i: i32, arg: Foo) {
match arg {
Foo::Bar(f) => f(i),
}
}
When I compile this piece of code I get the following error message:
error[E0161]: cannot move a value of type std::ops::FnOnce(i32) + 'static: the size of std::ops::FnOnce(i32) + 'static cannot be statically determined
--> src/main.rs:7:24
|
7 | Foo::Bar(f) => f(i),
| ^
Since I put the function in a Box
, I would have thought that that would deal with the problem of the compiler not knowing the size. How can I make the above program compile?
Here's the
FnOnce
trait's definition (simplified a little):To call a
FnOnce
closure, you need to be able to move the closure value itself into the invocation. Note thatself
has to be the actual closure type; aBox<FnOnce>
is a different type altogether.As a result, it's more or less impossible.
Now, there is a type in the standard library for dealing with just this situation:
FnBox
. Unfortunately, it's only recently been added, and thus cannot be used in stable Rust yet (that's the "or less" part).So, your choices are:
Box<FnOnce>
, you preserve the actual closure type.Box<FnMut>
instead.FnBox
to stabilise.It is unlikely
FnBox
becomes stable, but for the time being you can wrap theF: FnOnce(...) -> ...
in anOption<F>
, bind it in a mutable closure and unwrap and call it inside (so it panics if it gets called more than once); the resulting closure can be boxed asBox<FnMut(...) -> ...>
, which you might want to wrap somehow to make sure it only gets used ("called") once.See (my)
boxfnonce
crate.