Rust - Lifetimes


A lifetime is how long an object exists, i.e. the scope for which an object's reference is valid. Generally lifetimes are inferred in Rust, but sometimes annotations must be applied so the compile knows how long an object will be around for.

The syntax for explicit lifetimes are: 'a, where the 'a' can be any char (well variable string, but who needs more than 26 lifetimes?).

The lifetime annotations live in the same area as templates, and share the same < >.

Functions

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

fn main() {
    let s;
    let x = String::from("Apple");
    {
        let y = String::from("Pie");
        s = longest(&x, &y);
        println!("{}", s);
    }
    // print!("{}", s);  // y does not live long enough, therefor s cannot be used here
}

Rules

Lifetimes have three shortcut rules to make it easier for developers:

  1. Each parameter that is a reference gets its own lifetime
    • fn foo<'a, 'b>(x: &'a str, y: &'b str)
  2. If there is exactly one input lifetime parameter, that lifetime is applied to all output lifetime parameters
    • fn foo<'a>(x: &'a str) -> &'a str
  3. If an input lifetime parameter is &self or &mut self, the lifetime of self is automatically to all output lifetime parameters

Static Lifetimes

Static lifetimes live for the entire duration of the program. They have the 'static lifetime annotation.

fn main() {
    let s;
    {
        let x: &'static str = "LONG LIVE THE STATIC!";
        s = x;
    }
    println!("{}", s); // Static variable is still alive despite leaving scope
}

Structs

struct StringWrapper<'a> {
    s: &'a str,
}

impl<'a> StringWrapper<'a> {
    fn print(&self) {
        println!("{}", self.s);
    }

    fn get_s(&self) -> &str { // &str does not need a lifetime annotation because of the 3rd shortcut rule
        self.s
    }
}

fn main() {
    let wrapper;
    {
        let sentence = String::from("Apple Pie");
        let first_word = sentence.split(' ').next().expect("Need more than 1 word"); 
        wrapper = StringWrapper {
            s: first_word,
        };
        wrapper.print();
    };
    // wrapper.print();  // first_word, who's lifetime is on sentence, does not live long enough
}