为何已不再被借用的`s`会触发‘does not live long enough’错误?
Rust编译错误:
s生命周期问题解析 问题代码
struct F<'a>(Box<dyn Fn() + 'a>); fn main() { let mut v = vec![]; // Vec<F> let s = String::from("foo"); let f = F(Box::new(|| println!("{:?}", s))); v.push(f); drop(v); }
编译错误信息
error[E0597]: `s` does not live long enough --> src/main.rs:7:44 | 7 | let f = F(Box::new(|| println!("{:?}", s))); | -- ^ borrowed value does not live long enough | | | value captured here ... 11 | } | - | | | `s` dropped here while still borrowed | borrow might be used here, when `v` is dropped and runs the `Drop` code for type `Vec` | = note: values in a scope are dropped in the opposite order they are defined
疑问
明明手动调用了drop(v)让v先于s被释放,s被drop时已经没有被借用了,为什么编译器还提示s生命周期不足?
原因解析
Rust默认的变量drop顺序:Rust中同一作用域内的变量,会按照定义的逆序被drop——先定义的变量后释放,后定义的先释放。这里
v先定义,s后定义,所以默认情况下s会先被drop,v要等到s释放后才会被drop。静态生命周期检查不考虑手动drop:Rust的生命周期检查是静态编译期检查,它不会分析你手动调用
drop(v)这种运行时操作,只会依据变量的作用域范围和定义顺序来推导生命周期关系。生命周期不匹配的核心矛盾:
F<'a>中的闭包捕获了s的引用,编译器会把'a推导为s的生命周期。而v作为Vec<F<'a>>,它的作用域覆盖整个main函数直到结尾,编译器认为v中的F实例必须存活到作用域结束,这就要求'a(也就是s的生命周期)必须至少和v的作用域一样长。但按照默认drop顺序,s的生命周期比v短,当v最终被drop时,s已经不存在了,闭包的引用就会变成悬垂引用,因此编译器报错阻止这种不安全的情况。
简单说,编译器不认你手动提前drop的操作,它只认变量定义的顺序和作用域规则,默认判定v会在s之后被释放,这时候闭包引用的s已经消失,所以触发了生命周期错误。
内容的提问来源于stack exchange,提问作者keke
相关产品推荐
相关产品推荐

