How can I use a custom trait instead of FnMut with references?

The following code does not compile:

trait Fragment: FnMut(&i32) -> () {}

impl<T: FnMut(&i32) -> ()> Fragment for T {}

struct Foo {
    fun: Box<dyn Fragment>
}

impl Foo {
    fn foo(&mut self) -> impl Fragment + '_ {
        move |x| self.handler(x)
    }
    
    fn handler(&mut self, _x: &i32){
        {
            let y = 5;
            (self.fun)(&y);
        }
    }
}

An error occurs there:

error[E0271]: type mismatch resolving `for<'r> <[closure@src/lib.rs:13:9: 13:33 self:_] as std::ops::FnOnce<(&'r i32,)>>::Output == ()`
  --> src/lib.rs:12:26
   |
12 |     fn foo(&mut self) -> impl Fragment + '_ {
   |                          ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime
   |
   = note: required because of the requirements on the impl of `Fragment` for `[closure@src/lib.rs:13:9: 13:33 self:_]`
   = note: the return type of a function must have a statically known size

error[E0631]: type mismatch in closure arguments
  --> src/lib.rs:12:26
   |
12 |     fn foo(&mut self) -> impl Fragment + '_ {
   |                          ^^^^^^^^^^^^^^^^^^ expected signature of `for<'r> fn(&'r i32) -> _`
13 |         move |x| self.handler(x)
   |         ------------------------ found signature of `fn(&i32) -> _`
   |
   = note: required because of the requirements on the impl of `Fragment` for `[closure@src/lib.rs:13:9: 13:33 self:_]`
   = note: the return type of a function must have a statically known size

error: aborting due to 2 previous errors

Playground

But if I change return type of fn foo to the impl FnMut(&i32) -> () + '_ then this compile fine. Why it happens?

Lifetime inference is really bad for closures (especially around HRTB), so you need to manually annotate the types to force this to work. This is a known issue that the most general lifetime bounds won't be chosen by inference

1 Like

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