在闭包中通过引用保留值:Rust闭包生命周期编译错误解决
解决Rust闭包引用变量的生命周期编译错误
你遇到的问题是Rust编译器对闭包生命周期的默认推断和预期不一致导致的:虽然你已经给Foo和参数z指定了生命周期'a,但闭包默认会被推断为拥有更短的临时生命周期,编译器无法确认它不会超出z的存活范围,因此抛出了错误。
要让闭包通过引用使用z且不使用move关键字,核心是显式告诉编译器闭包的生命周期和z的'a完全一致,这样编译器就能确认闭包捕获的引用不会出现悬垂。
修改后的可行代码
struct Foo<'a> { x: Box<dyn Fn() + Send + Sync + 'a>, y: Box<dyn Fn() + Send + Sync + 'a>, } impl<'a> Foo<'a> { fn new(z: &'a str) -> Foo<'a> { // 显式标注闭包的类型,强制其生命周期与'a绑定 let x: Box<dyn Fn() + Send + Sync + 'a> = Box::new(|| { z; }); let y: Box<dyn Fn() + Send + Sync + 'a> = Box::new(|| { z; }); Foo { x, y } } }
你也可以用as做类型转换来达到同样效果:
impl<'a> Foo<'a> { fn new(z: &'a str) -> Foo<'a> { let x = Box::new(|| { z; }) as Box<dyn Fn() + Send + Sync + 'a>; let y = Box::new(|| { z; }) as Box<dyn Fn() + Send + Sync + 'a>; Foo { x, y } } }
原理说明
- 默认情况下,Rust会给闭包推断一个尽可能短的生命周期(通常是当前函数的调用周期),但我们需要闭包的生命周期和
z的'a绑定,才能和Foo的生命周期对齐。 - 通过显式指定闭包的类型包含
'a,相当于给编译器明确提示:这个闭包捕获的所有引用都不会超过'a的范围,而Foo的生命周期也是'a,因此闭包和Foo会同步存活,不会出现悬垂引用问题。 - 这种方式不需要使用
move关键字,因为我们只是约束了引用的生命周期,并没有转移z的所有权。
内容的提问来源于stack exchange,提问作者Will Squire
相关产品推荐
相关产品推荐

