Rust for C++

Lifetimes

Lifetimes ensure that the scope of a reference doesn't outlive the scope of the resource it is referring to.

Reference scope > Resource scope
#[derive(Debug)]
struct Foo {
    f : i32
}

fn main() {
    let x: &Foo;

    let a = Foo { f : 0 };

    x = &a;     // error: `a` does not live long enough

    println!("x: {:?}", x);
}
                     {     x     a      x=&a   }
reference x                <------------------->
lifetime #1                      <*************>
borrow                                  error
Resource scope >= Reference scope
#[derive(Debug)]
struct Foo {
    f :i32
}

fn main() {
    let a = Foo { f : 0 };

    let x: &Foo;

    x = &a;

    println!("x: {:?}", x);        // x: Foo { f: 0 }
}
                     {     a     x      x=&a    }
lifetime #1                <********************>
reference x                      <-------------->
borrow                                  ok

ANNOTATED LIFETIMES

Returned Lifetime

Returned lifetime = union of the scopes of all references linked to the returned address.

Wrong lifetime annotation
#[derive(Debug)]
struct Foo {
    f : i32
}

#[allow(unused_variables)]
fn f2<'b>(r2: &'b Foo, r3: &'b Foo) -> &'b Foo {
    r2
}

fn f1<'a>(r1: &'a Foo) -> &'a Foo {
    let s2 = Foo { f : 22 };
    let r4  = f2(&r1, &s2);
    r4
}

fn main() {
    let s1 = Foo { f : 11 };
    let r5 = f1(&s1);
    println!("r5: {:?}", r5);
}
                  { s1 { r1 s2 { r2 r3 } r4 } r5 }
resource s1         <****************************>

reference r1             <------------------>
reference r4                             <-->
reference r5                                  <-->
lifetime ‘a              <=======================>

reference r2                     <----->
reference r4                             <-->
reference r5                                  <-->
lifetime ‘b                      <===============>

resource s2                 <***************>


error: s2 does not live during the whole lifetime ‘b
Correct lifetime annotation
#[derive(Debug)]
struct Foo {
    f : i32
}

#[allow(unused_variables)]
fn f2<'b, 'c>(r2: &'b Foo, r3: &'c Foo) -> &'b Foo {
    r2
}

fn f1<'a>(r1: &'a Foo) -> &'a Foo {
    let s2 = Foo { f : 22 };
    let r4  = f2(&r1, &s2);
    r4
}

fn main() {
    let s1 = Foo { f : 11 };
    let r5 = f1(&s1);
    println!("r5: {:?}", r5);
}
                  { s1 { r1 s2 { r2 r3 } r4 } r5 }
resource s1         <****************************>

reference r1             <------------------>
reference r4                             <-->
reference r5                                  <-->
lifetime ‘a              <=======================>

reference r2                     <----->
reference r4                             <-->
reference r5                                  <-->
lifetime ‘b                      <===============>

resource s2                 <***************>

reference r3                        <-->
lifetime ‘c                         <==>

Struct field lifetime

Struct field lifetime = union of the scopes of all references linked to the address stored in that field.

Wrong lifetime annotation
#[derive(Debug)]
struct Foo {
    f : i32
}

#[derive(Debug)]
struct Bar<'b> {
    r4 : &'b Foo,
    r5 : &'b Foo
}

#[allow(unused_variables)]
fn f2<'b>(r2: &'b Foo, r3: &'b Foo) -> Bar<'b> {
    Bar { r4 : r2, r5 : r3 }
}

fn f1<'a>(r1: &'a Foo) -> &'a Foo {
    let s2 = Foo { f : 22 };
    let r6  = f2(&r1, &s2).r4;
    r6
}

fn main() {
    let s1 = Foo { f : 11 };
    let r7 = f1(&s1);
    println!("r7: {:?}", r7);
}
    { s1 { r1 s2 { r2 r3 { r4 r5 } } r4 r5 r6 } r7 } 
s1    <********************************************>

r1         <---------------------------------->
r4                                   <-------->
r6                                         <-->
r7                                              <-->
‘a         <=======================================>

r2                 <--------------->
r4                         <----->
r4                                   <-------->
r6                                         <-->
r7                                              <-->
‘b                 <===============================>


s2            <*******************************>




error: s2 does not live during the whole lifetime ‘b
Correct lifetime annotation
#[derive(Debug)]
struct Foo {
    f : i32
}

#[derive(Debug)]
struct Bar<'b, 'c> {
    r4 : &'b Foo,
    r5 : &'c Foo
}

#[allow(unused_variables)]
fn f2<'b, 'c>(r2: &'b Foo, r3: &'c Foo) -> Bar<'b, 'c> {
    Bar { r4 : r2, r5 : r3 }
}

fn f1<'a>(r1: &'a Foo) -> &'a Foo {
    let s2 = Foo { f : 22 };
    let r6  = f2(&r1, &s2).r4;
    r6
}

fn main() {
    let s1 = Foo { f : 11 };
    let r7 = f1(&s1);
    println!("r7: {:?}", r7);
}
    { s1 { r1 s2 { r2 r3 { r4 r5 } } r4 r5 r6 } r7 } 
s1    <********************************************>

r1         <---------------------------------->
r4                                   <-------->
r6                                         <-->
r7                                              <-->
‘a         <=======================================>

r2                 <--------------->
r4                         <----->
r4                                   <-------->
r6                                         <-->
r7                                              <-->
‘b                 <===============================>


s2            <*******************************>

r3                    <---------->
r5                            <-->
r5                                      <----->
‘c                    <=======================>