当U为引用时,如何为Fn(&T)->U中的U绑定&T的生命周期?
问题解答:为
Fn(&T) -> U中的引用类型U绑定生命周期 可以为引用类型的U绑定&T的生命周期,关键是要在map_ref方法中明确关联输入引用与返回值的生命周期关系。
原代码问题分析
原map_ref的签名没有约束闭包输入引用和返回值U的生命周期:
fn map_ref<U, F>(&self, f: F) -> Foo<U> where F: Fn(&T) -> U,
当U是引用类型时,编译器无法推断出返回的引用和&self(即&T的来源)的生命周期关联,会默认认为返回的引用可能有独立的生命周期,进而担心它会比self存活更久,导致悬空引用,因此编译报错。
修改方案
引入泛型生命周期'a,将&self的生命周期、闭包输入&T的生命周期,以及返回值U(如果是引用)的生命周期绑定在一起:
struct Foo<T>(T); impl<T> Foo<T> { fn map_ref<'a, U, F>(&'a self, f: F) -> Foo<U> where F: Fn(&'a T) -> U, { Foo(f(&self.0)) } } fn main() { let foo: Foo<i32> = Foo(42); let bar: Foo<i64> = foo.map_ref(|x| *x as i64); // 依然正常工作 let baz: Foo<&i32> = foo.map_ref(|x| x); // 现在编译通过 }
原理说明
通过'a生命周期参数,我们告诉编译器:
- 方法接收的
&self拥有生命周期'a - 闭包的输入参数
&T必须是&'a T(和self同生命周期) - 闭包返回的U如果是引用类型,其生命周期也必须是
'a
这样编译器就能确认,返回的Foo<&i32>中的引用不会超过foo的生命周期,不会出现悬空引用的问题,同时也保留了原方法对非引用类型U的支持(比如i64的情况)。
内容的提问来源于stack exchange,提问作者Lingxuan Ye
相关产品推荐
相关产品推荐

