最小可复现代码:
struct Foo<'a> {
name: &'a str,
}
impl<'a> Drop for Foo<'a> {
fn drop(&mut self) {
println!("{}", self.name);
}
}
fn main() {
let s0 = "老牛".to_string();
let mut foo = Foo { name: &s0 };
let s1 = "小牛".to_string();
foo.name = &s1;
}
获得编译错误:
error[E0597]: `s1` does not live long enough
--> src/main.rs:15:16
|
15 | foo.name = &s1;
| ^^^ borrowed value does not live long enough
16 | }
| -
| |
| `s1` dropped here while still borrowed
| borrow might be used here, when `foo` is dropped and runs the `Drop` code for type `Foo`
|
= note: values in a scope are dropped in the opposite order they are defined
For more information about this error, try `rustc --explain E0597`.
error: could not compile `playground` due to previous error
只要交换 s1
和 foo
的声明顺序,就可以通过编译。
我的问题是:这段代码为什么不能通过编译?
1
共 3 条评论, 1 页
评论区
写评论实际上用生命周期标注将每一个声明标注起来,问题就比较清晰了
为
'_
找出一个公共的生命周期值使得foo
周期内,& '_ String
都是活着的,否则就会导致dangling pointer的问题。因为编译器插入的代码导致foo
的生命周期是'b
,那么为了满足'_:'b
这个约束,'_
的值至少是'a
, 因为s1
的生命周期是'c
, 所以'c: 'a
不成立, 因此编译器会提示s1
does not live long enough.因为foo里面包含一个生命周期为a的引用,这个生命周期在初始化的时候被确定为s0的生命周期。
当你重新赋值的时候,新的生命周期和推断出来的不一致。
释放顺序和构造顺序相反,所以 s1 先被释放,再释放 foo,但是 s1 被释放的时候 foo 还活着,持有对 s1 的引用