Rust Lifetimes

Memory safety through lifetime annotations

⏰ What are Rust Lifetimes?

Lifetimes ensure references are valid for as long as needed. They prevent dangling pointers and memory safety issues by tracking how long data lives, making Rust memory-safe without garbage collection.


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

Lifetime Concepts

🔍

Implicit Lifetimes

Rust infers most lifetimes automatically

fn first_word(s: &str) -> &str {
    s.split_whitespace().next().unwrap_or("")
}
📝

Explicit Lifetimes

Manual annotations when needed

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

Struct Lifetimes

Lifetimes in struct definitions

struct ImportantExcerpt<'a> {
    part: &'a str,
}
🌍

Static Lifetime

Lives for entire program duration

let s: &'static str = "Hello, world!";

🔹 Basic Lifetime Example

Understanding how lifetimes work with references:

fn main() {
    let string1 = String::from("long string is long");
    
    {
        let string2 = String::from("xyz");
        let result = longest(string1.as_str(), string2.as_str());
        println!("The longest string is: {}", result);
    }
    // string2 goes out of scope here, but that's okay
    // because result was used before this point
}

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

Output:

The longest string is: long string is long

🔹 Lifetime Elision Rules

Rust can infer lifetimes in many cases:

🔸 Rule 1: Each parameter gets its own lifetime

// This function:
fn first_word(s: &str) -> &str {
    s.split_whitespace().next().unwrap_or("")
}

// Is equivalent to:
fn first_word<'a>(s: &'a str) -> &'a str {
    s.split_whitespace().next().unwrap_or("")
}

🔸 Rule 2: If one input lifetime, output gets same lifetime

// These are equivalent:
fn get_first_char(s: &str) -> &str { &s[0..1] }
fn get_first_char<'a>(s: &'a str) -> &'a str { &s[0..1] }

🔹 Structs with Lifetimes

When structs hold references, they need lifetime annotations:

struct ImportantExcerpt<'a> {
    part: &'a str,
}

impl<'a> ImportantExcerpt<'a> {
    fn level(&self) -> i32 {
        3
    }
    
    fn announce_and_return_part(&self, announcement: &str) -> &str {
        println!("Attention please: {}", announcement);
        self.part
    }
}

fn main() {
    let novel = String::from("Call me Ishmael. Some years ago...");
    let first_sentence = novel.split('.').next().expect("Could not find a '.'");
    
    let excerpt = ImportantExcerpt {
        part: first_sentence,
    };
    
    println!("Excerpt: {}", excerpt.part);
    println!("Level: {}", excerpt.level());
}

Output:

Excerpt: Call me Ishmael

Level: 3

🔹 Static Lifetime

The 'static lifetime lives for the entire program:

// String literals have 'static lifetime
let s: &'static str = "I have a static lifetime.";

// Static variables
static HELLO_WORLD: &str = "Hello, world!";

fn main() {
    println!("{}", s);
    println!("{}", HELLO_WORLD);
    
    // This function requires 'static lifetime
    let result = takes_static_str("This is a string literal");
    println!("{}", result);
}

fn takes_static_str(s: &'static str) -> &'static str {
    s
}

Output:

I have a static lifetime.

Hello, world!

This is a string literal

🔹 Multiple Lifetime Parameters

Functions can have multiple lifetime parameters:

fn announce_and_return_first<'a, 'b>(
    announcement: &'a str,
    x: &'b str,
    y: &'b str,
) -> &'b str {
    println!("Attention please: {}", announcement);
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

fn main() {
    let announcement = "Ladies and gentlemen";
    let string1 = String::from("long string is long");
    let string2 = String::from("short");
    
    let result = announce_and_return_first(
        announcement,
        string1.as_str(),
        string2.as_str(),
    );
    
    println!("The longest is: {}", result);
}

Output:

Attention please: Ladies and gentlemen

The longest is: long string is long

🧠 Test Your Knowledge

What does the 'static lifetime mean?