Lifetimes

https://doc.rust-lang.org/reference/lifetime-elision.html https://doc.rust-lang.org/reference/trait-bounds.html https://doc.rust-lang.org/reference/memory-allocation-and-lifetime.html

Now here comes of the more difficult things in Rust. All bindings in Rust have a "lifetime":

fn main() {
    // `x` doesn't exist yet
    {
        let x = 42; // `x` starts existing
        println!("x = {}", x);
        // `x` stops existing
    }
    // `x` no longer exists
}

Similarly, references have a lifetime:

fn main() {
    // `x` doesn't exist yet
    {
        let x = 42; // `x` starts existing
        let x_ref = &x; // `x_ref` starts existing - it borrows `x`
        println!("x_ref = {}", x_ref);
        // `x_ref` stops existing
        // `x` stops existing
    }
    // `x` no longer exists
}

The lifetime of a reference cannot exceed the lifetime of the variable binding it borrows:

fn main() {
    let x_ref = {
        let x = 42;
        &x
    };
    println!("x_ref = {}", x_ref);
    // error: `x` does not live long enough
}

A variable binding can be immutably borrowed multiple times:

fn main() {
    let x = 42;
    let x_ref1 = &x;
    let x_ref2 = &x;
    let x_ref3 = &x;
    println!("{} {} {}", x_ref1, x_ref2, x_ref3);
}

While borrowed, a variable binding cannot be mutated:

fn main() {
    let mut x = 42;
    let x_ref = &x;
    x = 13;
    println!("x_ref = {}", x_ref);
    // error: cannot assign to `x` because it is borrowed
}

While immutably borrowed, a variable cannot be mutably borrowed:

fn main() {
    let mut x = 42;
    let x_ref1 = &x;
    let x_ref2 = &mut x;
    // error: cannot borrow `x` as mutable because it is also borrowed as immutable
    println!("x_ref1 = {}", x_ref1);
}

References in function arguments also have lifetimes. however, most of the time it is not specified (lifetime elision):

#![allow(unused)]
fn main() {
fn print(x: &i32) {
    // `x` is borrowed (from the outside) for the
    // entire time this function is called.
}
}

Functions with reference arguments can be called with borrows that have different lifetimes, so:

  • All functions that take references are generic
  • Lifetimes are generic parameters
  • Lifetimes' names start with a single quote, ':
#![allow(unused)]
fn main() {
// elided (non-named) lifetimes:
fn print(x: &i32) {}

// named lifetimes:
fn print<'a>(x: &'a i32) {}
}

There is a special lifetime, named 'static, which is valid for the entire program's lifetime.

String literals are 'static:

struct Person {
    name: &'static str,
}

fn main() {
    let p = Person {
        name: "Satoshi Nakamoto",
    };
}