Rust定义支持可选引用类型fn参数的MapValue trait遇生命周期错误如何解决
第一个标注错误的原因
你最初的报错和第一次修改后的生命周期报错,根源是trait定义中没有关联Out的生命周期和self的生命周期:
- 你第一次写的
impl MapValue<&i32> for i32中,&i32被Rust自动推导为高阶生命周期for<'a> &'a i32,而方法中self的生命周期是方法自身的匿名生命周期,和高阶生命周期不匹配,所以出现函数指针类型不匹配的报错。 - 你尝试给
impl加生命周期'a并标注&'a self,但trait的map_value方法中self的生命周期是匿名的,impl的方法签名和trait定义不匹配,trait要求self的生命周期由调用方决定,不能和impl层面的'a绑定,所以报生命周期不匹配的错误。
你之后把trait修改为带生命周期参数的版本,解决了第一个问题,因为此时'a是trait的泛型参数,self的生命周期和Out的生命周期明确绑定。
第二个场景的错误原因与解决方案
第二个场景的报错核心是:你把引用的生命周期'a声明在了impl层面,这个生命周期是调用方指定的,要求至少和实例的生命周期一样长,甚至更长。但你函数内的局部变量cpy的生命周期只在函数执行期间,远短于调用方指定的'a,自然无法满足生命周期约束。你逻辑上认为map_func调用在函数返回前就结束,不需要引用存活更久,说明你需要的是**map_func只要求第二个参数在自身调用期间有效,不需要和外部生命周期绑定**。
解决方案
方案1:使用泛型关联类型(GAT,Rust 1.65+ 稳定支持)
GAT允许你把输出类型的生命周期绑定到方法调用的生命周期,而非trait或impl层面,完美适配两种场景:
pub trait MapValue { type Output<'a> where Self: 'a; fn map_value<C>(&self, map_func: fn(C, Self::Output<'_>), context: C); } // 场景1:输出i32值 impl MapValue for i32 { type Output<'a> = i32; fn map_value<C>(&self, map_func: fn(C, i32), context: C) { map_func(context, *self); } } // 场景2:输出self的引用 impl MapValue for &i32 { type Output<'a> = &'a i32 where Self: 'a; fn map_value<C>(&self, map_func: fn(C, &'_ i32), context: C) { map_func(context, self); } } // 场景3:输出局部变量的引用 struct LocalI32(i32); impl MapValue for LocalI32 { type Output<'a> = &'a i32 where Self: 'a; fn map_value<C>(&self, map_func: fn(C, &'_ i32), context: C) { let cpy = self.0; // 此时Output的生命周期仅和map_func调用周期匹配,不会报错 map_func(context, &cpy); } }
方案2:稳定版无GAT方案
如果需要兼容更低版本的Rust,可以针对临时引用的场景单独使用高阶生命周期约束(HRTB)定义trait:
// 输出临时引用的专属trait pub trait MapLocalRefValue { // for<'f> 表示函数指针接受任意生命周期的&i32,只要调用期间有效即可 fn map_value<C>(&self, map_func: for<'f> fn(C, &'f i32), context: C); } impl MapLocalRefValue for i32 { fn map_value<C>(&self, map_func: for<'f> fn(C, &'f i32), context: C) { let cpy = *self; map_func(context, &cpy); } }
内容的提问来源于stack exchange,提问作者Gerharddc
相关产品推荐
相关产品推荐

