Error implementing a trait for FnOnce

I would like to implement a trait for FnOnce but I get an error that I don't understand:

pub trait Something{}

pub trait MyTrait {
    fn do_it<E: Something>(&self, smt: &mut E);
}

impl<F> MyTrait for F
    where
        F: FnOnce(&mut dyn Something),
{
    fn do_it<E: Something>(&self, smt: &mut E) {
        (self)(smt)
    }
}

The compiler complains that:

error[E0507]: cannot move out of `*self` which is behind a shared reference
  --> src/my_test.rs:26:9
   |
26 |         (self)(smt)
   |         ^^^^^^ move occurs because `*self` has type `F`, which does not implement the `Copy` trait

If I replace FnOnce with Fn then it works, but I need it for FnOnce.
Any way to make it work?

You need to either: consume self by value (not by shared reference)

pub trait Something{}

pub trait MyTrait {
    fn do_it<E: Something>(self, smt: &mut E);
}

impl<F> MyTrait for F
    where
        F: FnOnce(&mut dyn Something),
{
    fn do_it<E: Something>(self, smt: &mut E) {
        (self)(smt)
    }
}

or change the bounds from FnOnce to Fn

pub trait Something{}

pub trait MyTrait {
    fn do_it<E: Something>(&self, smt: &mut E);
}

impl<F> MyTrait for F
    where
        F: Fn(&mut dyn Something),
{
    fn do_it<E: Something>(&self, smt: &mut E) {
        (self)(smt)
    }
}

This is because FnOnce needs to consume the value in order to call the closure, whereas Fn only needs a shared reference in order to call the closure.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.