如何为Rust柯里化函数实现trait?Frob trait实现报E0599错误如何解决
报错解读
- 这条报错的核心是编译器找不到能匹配foo函数的
Frobtrait实现,后面的note提到的FnOnce::Output = _不满足只是表层现象,根本原因是生命周期约束缺失:- 你的
foo函数返回的闭包携带了输入state参数的生命周期'b,也就是说返回的闭包类型和入参引用的生命周期强绑定 - 你当前写的
Frob实现中,泛型参数G是impl级别的固定类型,但是F: FnMut(&mut S) -> G这个约束里的&mut S没有显式生命周期声明,编译器无法将返回的G的生命周期和入参&mut S的生命周期关联起来 - 生命周期是Rust类型的一部分,不同生命周期的闭包属于不同类型,固定的泛型
G无法匹配所有可能生命周期下的返回值类型,因此约束校验失败
- 你的
正确约束编写方案
有两种常用的实现方案,分别对应不同的Rust版本要求:
方案1:动态装箱(兼容所有稳定版Rust)
把返回的闭包装箱为特征对象,消弭生命周期带来的类型差异,修改后的实现如下:
trait Frob<S, I, O> { fn frob(self, state: &mut S, input: I) -> O; } impl<S, I, O, F> Frob<S, I, O> for F where // 用高阶生命周期绑定,说明对任意生命周期'a,F都能接收&'a mut S,返回绑定了'a生命周期的闭包特征对象 F: for<'a> FnMut(&'a mut S) -> Box<dyn FnMut(I) -> O + 'a>, { fn frob(mut self, state: &mut S, input: I) -> O { let mut g = self(state); g(input) } } // 对应的foo函数也要调整返回值为装箱的特征对象 fn foo<'b>(state: &'b mut i32) -> Box<dyn FnMut(&str) -> i32 + 'b> { Box::new(move |i| *state) } fn bar() { foo.frob(&mut 1, "hi"); }
方案2:使用GAT+RPITIT(Rust 1.65及以上版本,无运行时开销)
如果不想承担动态装箱的性能开销,可以用泛型关联类型(GAT)来声明和生命周期绑定的返回值类型:
trait Frob<S, I, O> { // 声明关联类型,和输入state的生命周期'a绑定 type FnOutput<'a>: FnMut(I) -> O + 'a where Self: 'a, S: 'a; fn frob<'a>(self, state: &'a mut S, input: I) -> O; } impl<S, I, O, F> Frob<S, I, O> for F where F: for<'a> FnMut(&'a mut S) -> <Self as Frob<S, I, O>>::FnOutput<'a>, { type FnOutput<'a> = impl FnMut(I) -> O + 'a where Self: 'a, S: 'a; fn frob<'a>(mut self, state: &'a mut S, input: I) -> O { let mut g = self(state); g(input) } } // foo函数不需要修改,保留原来的impl trait返回即可 fn foo<'b>(state: &'b mut i32) -> impl FnMut(&str) -> i32 + 'b { move |i| *state } fn bar() { foo.frob(&mut 1, "hi"); }
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

