How to resolve closure move issue?


fn test<F>(f: F)
where
    F: Fn(i32) + 'static + Send + Sync,
{
    test2(move || test3(f))
}

fn test2<F>(f: F)
where
    F: Fn() + 'static + Send + Sync,
{}

fn test3<F>(f: F)
where
    F: FnOnce(i32) + 'static + Send + Sync,
{}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0507]: cannot move out of `f`, a captured variable in an `Fn` closure
 --> src/lib.rs:6:25
  |
2 | fn test<F>(f: F)
  |            - captured outer variable
...
6 |     test2(move || test3(f))
  |           -------       ^ move occurs because `f` has type `F`, which does not implement the `Copy` trait
  |           |
  |           captured by this `Fn` closure
  |
help: if `F` implemented `Clone`, you could clone the value
 --> src/lib.rs:2:9
  |
2 | fn test<F>(f: F)
  |         ^ consider constraining this type parameter with `Clone`
...
6 |     test2(move || test3(f))
  |                         - you could clone this value

warning: unused variable: `f`
 --> src/lib.rs:9:13
  |
9 | fn test2<F>(f: F)
  |             ^ help: if this is intentional, prefix it with an underscore: `_f`
  |
  = note: `#[warn(unused_variables)]` on by default

warning: unused variable: `f`
  --> src/lib.rs:14:13
   |
14 | fn test3<F>(f: F)
   |             ^ help: if this is intentional, prefix it with an underscore: `_f`

For more information about this error, try `rustc --explain E0507`.
warning: `playground` (lib) generated 2 warnings
error: could not compile `playground` (lib) due to 1 previous error; 2 warnings emitted

if you can change signature of test2(), change it to accept FnOnce instead of Fn can fix the error, i.e.:

fn test2<F>(f: F)
where
    F: FnOnce() + 'static + Send + Sync,
{}

alternatively, if you can change test3() to use Fn instead of FnOnce, it will do too.

if you cannot change test2() nor test3(), then the compilers' suggestion is the only possible fix, which requires you to change test1():

fn test<F>(f: F)
where
    F: Fn(i32) + 'static + Send + Sync + Clone,
{
    test2(move || test3(f.clone()))
}

if you cannot change any signatures, then you'll not be able to use this closure to call test2():

move || test3(f)

You can build your own F: Fn(..) + Clone without changing the bounds.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.