通用寿命是作为参考寿命或参考值的寿命实现吗?

时间:2019-08-12 05:57:19

标签: rust lifetime

考虑以下程序:

fn main() {
    let c;                                      |<-'a
    let mut a = "Hello, world!".to_string();    |
    {                                           |
        let b = &mut a;           |<-'b         |
        c = foo(b);               |             |
    }                                           |
    println!("{}", c)                           |
}

fn foo<'z>(a: &'z mut str) -> &'z str {
    a
}

b的生存期为'b,但是c的生存期为'a,比'b长。 foo的生存期约束表明foo的返回值(在这种情况下为c)与其参数(在这种情况下为b)具有相同的生存期。 foo的生命周期约束如何得到满足?

但是,该程序会编译,因此我猜想foo的生存期参数'zb的参考值(a)的生存期的真实体现,因此{ {1}}的生命周期约束得到满足吗?

1 个答案:

答案 0 :(得分:2)

值具有其自身的生存期,但是引用也跟踪其引用的事物的生存期。不幸的是,这里缺少官方术语。我(和其他一些人)已经开始使用的术语是具体寿命。主要变量有三个,因此有三个具体寿命:

fn main() {
    let c;                     //       'c
    let mut a = String::new(); // 'a     ¦
    {                          //  |     ¦
        let b = &mut a;        //  | 'b  ¦
        c = foo(b);            //  |  |  |
    }                          //  |     |
    println!("{}", c)          //  |     |
}

aStringb&mut String,而c&str。这三个变量都是值,但是bc也是也是引用。在这种情况下,b是指a中的值,并且是&'a mut String。由于c源自b,因此它具有相同的“内部寿命”:&'a str

值得注意的是,b本身的生存期从不发挥作用。它非常罕见,因为您需要可变的借贷和“额外的”借贷:

fn main() {
    let c;
    let mut a = String::new();
    {
        let mut b = &mut a;
        c = foo(&mut b);    // Mutably borrowing `b` here
    }
    println!("{}", c)
}
error[E0597]: `b` does not live long enough
 --> src/main.rs:6:17
  |
6 |         c = foo(&mut b);
  |                 ^^^^^^ borrowed value does not live long enough
7 |     }
  |     - `b` dropped here while still borrowed
8 |     println!("{}", c)
  |                    - borrow later used here

在这种情况下,传递给foo的值的类型为&'b mut &'a mut String,其值被强制下调为&'b mut str。值b的寿命不足,就会出现错误。

  

我认为该模型无法解释更复杂的借贷关系。例如,如果在a之后再次使用println!,则可变借项不能在a的整个生命周期中使用

a的可变借项由c持有,但是借用的持续时间不需要与c的生存期相对应。由于non-lexical lifetimes(在此情况下称为“非词汇借用”),由a持有的c的借用可以在println!之后但在范围。

从上方增强该图以显示的寿命以及括号中引用的值的寿命:

fn main() {
    let c;                     //           'c
    let mut a = String::new(); // 'a         ¦
    {                          //  |         ¦
        let b = &mut a;        //  | 'b('a)  ¦
        c = foo(b);            //  |  |('a)  |('a)
    }                          //  |         |('a)
    println!("{}", c);         //  |         |('a)
                               //  |         |
    println!("{}", a);         //  |         |
}

另请参阅: