Why is calling a FnOnce closure a move?
Asked Answered
W

1

8

I'm trying to pass in a closure to a function that will then mutate something passed into it within the scope of the function. Based on my current understanding of Rust, that should look something like this:

pub fn call_something(callback: &FnOnce(&mut Vec<i32>)) {
    let mut my_vec = vec![0, 1, 2, 3, 4];
    callback(&mut my_vec);
}

That results in these errors:

error[E0161]: cannot move a value of type dyn for<'r> std::ops::FnOnce(&'r mut std::vec::Vec<i32>): the size of dyn for<'r> std::ops::FnOnce(&'r mut std::vec::Vec<i32>) cannot be statically determined
 --> src/lib.rs:3:5
  |
3 |     callback(&mut my_vec);
  |     ^^^^^^^^

error[E0507]: cannot move out of borrowed content
 --> src/lib.rs:3:5
  |
3 |     callback(&mut my_vec);
  |     ^^^^^^^^ cannot move out of borrowed content

Why is calling a FnOnce a move? What am I missing here?

Workhorse answered 9/11, 2018 at 22:1 Comment(0)
C
9

Why is calling a FnOnce a move?

Because that's the definition of what makes a closure FnOnce:

extern "rust-call" fn call_once(self, args: Args) -> Self::Output
//                              ^^^^

Contrast this to FnMut and Fn:

extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output
//                             ^^^^^^^^^
extern "rust-call" fn call(&self, args: Args) -> Self::Output
//                         ^^^^^

See also:


You probably want

pub fn call_something(callback: impl FnOnce(&mut Vec<i32>))

or

pub fn call_something<F>(callback: F)
where
    F: FnOnce(&mut Vec<i32>),

These are identical. They both take ownership of the closure, which means that you can call the closure and consume it in the process.

Carolinian answered 9/11, 2018 at 22:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.