Expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce`

fn main(){
    let mut x = String::new();
    let y = || {
        let t = x;
    };
    let mut ww = Box::new(y);
    ww();
}

I expect it to run without any error as this implementation exist

impl<Args, F, A> FnOnce<Args> for Box<F, A>

But I am getting some weird errors which I am unable to understand why?

error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce`
  --> src/main.rs:22:13
   |
22 |     let y = || {
   |             ^^ this closure implements `FnOnce`, not `FnMut`
23 |         let t = x;
   |                 - closure is `FnOnce` because it moves the variable `x` out of its environment
...
26 |     ww();
   |     ---- the requirement to implement `FnMut` derives from here

error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
  --> src/main.rs:22:13
   |
22 |     let y = || {
   |             ^^ this closure implements `FnOnce`, not `Fn`
23 |         let t = x;
   |                 - closure is `FnOnce` because it moves the variable `x` out of its environment
...
26 |     ww();
   |     ---- the requirement to implement `Fn` derives from here
1 Like

Presumably, you meant this:

    let mut x = String::new();
    let y = || {
        let t = &mut  x;
    };
    let mut ww = Box::new(y);
    ww();

No I didnt. But the changed code wont compile as well.

Rust has a concept of single ownership, i.e. a String type can have at most one owner. It can't exist in two places.

Moves preserve this single-ownership rule by allowing you to move a variable once and no more.

let t = x moves x to t every time the method is called, but because value can be moved only once, then the only correct way to use this closure is to call it once.

You need to capture &x inside the closure (not &mut, they're single-owned too). Shared references can be copied any number of times.

    let mut x = String::new();
    let x_ref = &x;
    let y = || {
        let t = x_ref;
    };

Alternatively make it a move || closure that owns the x, but don't move or destroy it inside the closure, e.g. borrowing temporarily doesn't move it further move || { x.len() }.

If you want to use this string inside and outside of the closure, you'll need Arc<String>. If you want to also mutate it, then Arc<Mutex<String>>.

3 Likes

I have only called it once.

Something tells Rust that it can be called many times (e.g. if you're returning it, or implementing a trait).

Try:

let mut ww: Box<dyn FnOnce()> = Box::new(y);

Indeed, if you hint that Box<dyn FnOnce() + 'static> is expected, it compiles. So this is a type inference failure (with an unhelpful error message).

Somewhat similar issue: Misleading diagnostic when type inference for `Box<dyn FnOnce()>` fails · Issue #85567 · rust-lang/rust · GitHub

1 Like

Just updated the code . I know there are ways to make it work. I wanna know why it doesnt compile. I am just trying to understand Fn* traits better.

It's an inference failure, as cole-miller said.
The following works:

fn main(){
    let mut x = String::new();
    let y = || {
        let t = x;
    };
    let mut ww = Box::new(y);
    (*ww)();
}

See also: Stack Overflow discussion

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.