"cannot move a value of type FnOnce" when moving a function in a box

I'm trying to make some higher order programs in Rust, but I'm having difficulty closing. Here is a piece of code that illustrates one of the problems that I am 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 Box , I would think that this would deal with the compiler problem without knowing the size. How to compile the above program?

+9
rust
source share
2 answers

Here is the definition of the FnOnce (slightly simplified):

 pub trait FnOnce<Args> { type Output; fn call_once(self, args: Args) -> Self::Output; } 

To trigger a FnOnce closure, you must be able to move the closure value itself to the call. Note that self must be the actual type of closure; Box<dyn FnOnce> is a completely different type.

Rust 1.35

Box<dyn FnOnce> can now be called; Your original code works as is.

Previous Versions

There is a type in the standard library to work around this situation: FnBox . Unfortunately, this is unstable.

Your alternative choice:

  • Modify the code so that instead of Box<FnOnce> you keep the actual type of closure.
  • Box<FnMut> this use Box<FnMut> .
  • Wait for the FnBox stabilize.
  • Switch to the night compiler.
+14
source share

It is unlikely that FnBox becoming stable, but for now you can wrap F: FnOnce(...) -> ... in Option<F> , bind it in mutable closure and expand it and call it inside (so that it panics if it is called more than once); the resulting closure can be marked as Box<FnMut(...) -> ...> , which you might want to wrap in some way to make sure that it is only used once ("called").

See (my) boxfnonce crate.

+1
source share

All Articles