Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I implement a trait on a curried function?

Tags:

rust

If I try to implement the trait Frob for functions like foo as follows:

fn foo<'b>(state: &'b mut i32) -> impl FnMut(&str) -> i32 + 'b {
    move |i| *state
}

trait Frob<S, I, O> {
    fn frob(self, state: &mut S, input: I) -> O;
}

impl<S, I, O, F, G> Frob<S, I, O> for F
where
    F: FnMut(&mut S) -> G,
    G: FnMut(I) -> O,
{
    fn frob(mut self, state: &mut S, input: I) -> O {
        self(state)(input)
    }
}

fn bar() {
    foo.frob(&mut 1, "hi");
}

I get the error

error[E0599]: the method `frob` exists for fn item `for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo}`,
but its trait bounds were not satisfied
...
   = note: the following trait bounds were not satisfied:
           `<for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo} as FnOnce<(&mut _,)>>::Output = _`
           which is required by `for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo}: Frob<_, _, _>`
           `<&for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo} as FnOnce<(&mut _,)>>::Output = _`
           which is required by `&for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo}: Frob<_, _, _>`
           `<&mut for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo} as FnOnce<(&mut _,)>>::Output = _`
           which is required by `&mut for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo}: Frob<_, _, _>`

First of all, how do I interpret this error message? Second, how do I write the trait bound correctly? Presumably the problem has something to do with the returned closure hanging on to state, but I can't find a place to specify a lifetime for G.

like image 321
Dan Avatar asked Jan 20 '26 07:01

Dan


1 Answers

  1. First of all, how do I interpret this error message?

    Yes, it is a tad cryptic isn't it? Two things to recognise:

    • <for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo} is the compiler's very wordy way of expressing the type of function foo; and

    • the same note is repeated for that function type, a shared reference to that function type, and a mutable reference to that function type—this happens when the compiler attempts automatic referencing in method call syntax such as you have in foo.frob(...).

    So we can quickly distill the error message down to:

    error[E0599]: the method `frob` exists for fn item `{foo}`,
    but its trait bounds were not satisfied
    ...
       = note: the following trait bounds were not satisfied:
               `<{foo} as FnOnce<(&mut _,)>>::Output = _`
               which is required by `{foo}: Frob<_, _, _>`
    

    The compiler is telling us that it found a potential frob method on {foo} but in order for it to be applicable, {foo}'s return type must match the constraints of the Frob trait (but it doesn't).

  2. Second, how do I write the trait bound correctly? Presumably the problem has something to do with the returned closure hanging on to state, but I can't find a place to specify a lifetime for G.

    You need to add the lifetime constraint to the trait (playground):

     trait Frob<'b, S, I, O> {
         fn frob(self, state: &'b mut S, input: I) -> O;
     }
    
     impl<'b, S: 'b, I, O, F, G> Frob<'b, S, I, O> for F
     where
         F: FnMut(&'b mut S) -> G,
         G: 'b + FnMut(I) -> O,
     {
         fn frob(mut self, state: &'b mut S, input: I) -> O {
             self(state)(input)
         }
     }
    
like image 163
eggyal Avatar answered Jan 23 '26 05:01

eggyal



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!