< 返回版块

hzqd 发表于 2023-01-23 02:16

Tags:生命周期

最小可复现代码:

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

只要交换 s1foo 的声明顺序,就可以通过编译。

我的问题是:这段代码为什么不能通过编译?

评论区

写评论
xmh0511 2023-01-31 13:35

实际上用生命周期标注将每一个声明标注起来,问题就比较清晰了

fn main() {
    'a:{
        let s0 = "老牛".to_string();
        'b:{
           let mut foo = Foo { name: & '_ s0 };
           'c:{
              let s1 = "小牛".to_string(); 
              foo.name = & '_ s1;
           }
           drop(foo); // 编译器插入的代码
        }
    }
}

'_找出一个公共的生命周期值使得foo周期内,& '_ String都是活着的,否则就会导致dangling pointer的问题。因为编译器插入的代码导致foo的生命周期是'b,那么为了满足'_:'b这个约束,'_的值至少是'a, 因为s1的生命周期是'c, 所以'c: 'a不成立, 因此编译器会提示s1 does not live long enough.

MrZLeo 2023-01-23 09:30

因为foo里面包含一个生命周期为a的引用,这个生命周期在初始化的时候被确定为s0的生命周期。

当你重新赋值的时候,新的生命周期和推断出来的不一致。

LightQuantum 2023-01-23 06:44

释放顺序和构造顺序相反,所以 s1 先被释放,再释放 foo,但是 s1 被释放的时候 foo 还活着,持有对 s1 的引用

1 共 3 条评论, 1 页