12
fn make_adder(x: String) -> Box<Fn() -> String> {
    Box::new(|| x)
}

fn main() {
    make_adder(String::from("a"));
}

This results in this error:

error[E0507]: cannot move out of captured outer variable in an `Fn` closure
 --> src/main.rs:2:17
  |
1 | fn make_adder(x: String) -> Box<Fn() -> String> {
  |               - captured outer variable
2 |     Box::new(|| x)
  |                 ^ cannot move out of captured outer variable in an `Fn` closure

How can I make it correct?

Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305
Dajavu
  • 381
  • 4
  • 5
  • Possible duplicate of [When should I add mut to closures?](https://stackoverflow.com/questions/49986734/when-should-i-add-mut-to-closures) – ljedrz Apr 24 '18 at 11:27
  • 3
    For people thinking about closing this as a dupe: There are similar questions like [" Cannot move out of captured outer variable in an `Fn` closure "](https://stackoverflow.com/questions/33662098/cannot-move-out-of-captured-outer-variable-in-an-fn-closure) or ["How can I move a captured variable into a closure within a closure? "](https://stackoverflow.com/questions/28521637/how-can-i-move-a-captured-variable-into-a-closure-within-a-closure), but both have examples far from *minimal*. I'd propose to keep this question as it has a nice small example. – Lukas Kalbertodt Apr 24 '18 at 11:28
  • Change `Fn` to `FnOnce`. – ljedrz Apr 24 '18 at 11:28
  • 2
    @LukasKalbertodt a duplicate still serves as an example; the linked questions contain the answer. – ljedrz Apr 24 '18 at 11:30

1 Answers1

17

A closure which implements Fn can be called multiple times (the receiver parameter is &self, an immutable reference to the closure):

fn call_multiple_times<F: Fn(u8) -> i32>(f: F) {
    // Works! We can call the closure mutliple times
    let a = f(1);
    let b = f(27);
    let c = f(31);
}

This means that with your closure Fn() -> String, you could do this:

let s1 = adder();
let s2 = adder();

Now you would have two Strings although you only started with one! Magic? You can of course get another string by cloning the original string, but we don't do that here. So it clearly can't work.


You can fix that in two ways. Either you don't need your closure to be called multiple times. In that case you can simply change Fn to FnOnce (a less demanding trait). An FnOnce closure can only be called ... well ... once. This works:

fn make_adder(x: String) -> Box<FnOnce() -> String> {
    Box::new(|| x)
}

On the other hand, maybe you want the closure to be called multiple times and always want to return a new clone of the string. You can do that like this:

fn make_adder(x: String) -> Box<Fn() -> String> {
    Box::new(move || x.clone())
}

Here we added a .clone() call (since in Rust, deep clones are never implicit!) and we added the move keyword. The latter is necessary to explicitly move the string x into the closure, not just borrow it.

Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305