首页 > 解决方案 > 如何在柯里化函数上实现特征?

问题描述

如果我尝试为如下Frob函数实现特征:foo

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");
}

我得到错误

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<_, _, _>`

首先,我该如何解释这个错误信息?其次,如何正确编写特征绑定?大概这个问题与返回的闭包挂在 上有关state,但我找不到一个地方来指定G.

标签: rust

解决方案


  1. 首先,我该如何解释这个错误信息?

    是的,这有点神秘,不是吗?有两点需要识别:

    • <for<'b> fn(&'b mut i32) -> impl for<'b, 'r> FnMut<(&'r str,)> {foo}是编译器非常罗嗦的表达函数类型foo的方式;和

    • 对于该函数类型、对该函数类型的共享引用和对该函数类型的可变引用重复相同的注释——当编译器尝试在方法调用语法中自动引用时会发生这种情况,例如您在foo.frob(...).

    因此,我们可以快速将错误消息提炼为:

    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<_, _, _>`
    

    编译器告诉我们它找到了一个潜在的frob方法,{foo}但为了使其适用,{foo}的返回类型必须匹配特征的约束Frob(但它不匹配)。

  2. 其次,如何正确编写特征绑定?大概这个问题与返回的闭包挂在 上有关state,但我找不到一个地方来指定G.

    您需要将生命周期约束添加到特征(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)
         }
     }
    

推荐阅读