1

I store a FnOnce closure inside a struct inside an enum (Rust Playground):

pub struct ClosureContainer {
    closure: Box<dyn FnOnce(i32) -> i32>,
}

pub enum MathOperation {
    DoNothing,
    RunOperation(ClosureContainer),
}

impl MathOperation {
    pub fn doMath(&self, input: i32) -> i32 {
        match self {
            MathOperation::DoNothing => input,
            MathOperation::RunOperation(closureContainer) => (closureContainer.closure)(input),
        }
    }
}

fn main() {
    let f = Box::new(move |input: i32| 4 * input);
    let closureContainer = ClosureContainer { closure: f };
    let operation = MathOperation::RunOperation(closureContainer);
    println!("{}", operation.doMath(5));
}

When I try to build, I get this error:

error[E0507]: cannot move out of `closureContainer.closure` which is behind a shared reference
  --> src/main.rs:14:62
   |
14 |             MathOperation::RunOperation(closureContainer) => (closureContainer.closure)(input),
   |                                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because `closureContainer.closure` has type `Box<dyn FnOnce(i32) -> i32>`, which does not implement the `Copy` trait

How do I set things up so that I can call this function?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
zv777mnw
  • 93
  • 3
  • 1
    Your question might be answered by the answers of [FnOnce inside Enum: cannot move out of borrowed content](https://stackoverflow.com/q/32236430/155423). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster May 09 '22 at 16:45
  • 1
    See also [Why is calling a FnOnce closure a move?](https://stackoverflow.com/q/53233803/155423) – Shepmaster May 09 '22 at 16:47

1 Answers1

2

FnOnce can only be called once, so it needs to be consumed. If it's consumed, then the ClosureContainer must also be consumed (otherwise it's just an invalid struct). The fix, then, is to use self instead of &self in doMath:

pub struct ClosureContainer {
    closure: Box<dyn FnOnce(i32) -> i32>,
}

pub enum MathOperation {
    DoNothing,
    RunOperation(ClosureContainer),
}

impl MathOperation {
    pub fn doMath(self, input: i32) -> i32 {
        match self {
            MathOperation::DoNothing => input,
            MathOperation::RunOperation(closureContainer) => (closureContainer.closure)(input),
        }
    }
}

fn main() {
    let f = Box::new(move |input: i32| 4 * input);
    let closureContainer = ClosureContainer { closure: f };
    let operation = MathOperation::RunOperation(closureContainer);
    println!("{}", operation.doMath(5));
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
zv777mnw
  • 93
  • 3