Rust Lesson 17 – Lifetimes | Dataplexa

Lifetimes in Rust

In this lesson, you will learn about lifetimes in Rust. Lifetimes describe how long references are valid.

They are one of the most powerful features of Rust and help prevent dangling references and memory errors at compile time.


What Is a Lifetime?

A lifetime is the scope for which a reference is valid. It ensures that references never outlive the data they point to.

Rust uses lifetimes to guarantee memory safety without a garbage collector.


Why Lifetimes Are Needed

Consider this situation:

fn main() {
    let r;

    {
        let x = 5;
        r = &x;
    }

    println!("{}", r);
}

This code is invalid because x goes out of scope before r is used.

Rust detects this issue at compile time and prevents the program from running.


Lifetime Annotation Syntax

Lifetime annotations use an apostrophe followed by a name, such as 'a.

They do not change how long a reference lives — they only describe relationships between lifetimes.

&'a i32
&'a str

Lifetimes in Functions

When a function returns a reference, Rust must know how the input and output lifetimes relate.

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

This function tells Rust that the returned reference will live as long as both input references.


Using the Function

Here is how the lifetime-annotated function works in practice:

fn main() {
    let s1 = String::from("Rust");
    let s2 = String::from("Programming");

    let result = longest(&s1, &s2);
    println!("{}", result);
}

Lifetime Elision

In many cases, Rust can infer lifetimes automatically. This is called lifetime elision.

For example, this function does not require explicit lifetime annotations:

fn first_word(s: &str) -> &str {
    &s[..1]
}

Rust applies built-in rules to infer the correct lifetimes.


Lifetimes in Structs

Structs that store references must also use lifetime annotations.

struct Book<'a> {
    title: &'a str,
}

This ensures that the reference inside the struct does not outlive the data it points to.


Lifetimes and Methods

Lifetime annotations are often used in method definitions.

impl<'a> Book<'a> {
    fn title(&self) -> &str {
        self.title
    }
}

Here, Rust automatically understands the lifetime of &self.


Common Lifetime Errors

Some common lifetime-related errors include:

  • Returning references to local variables
  • Using references after data goes out of scope
  • Mismatched input and output lifetimes

Why Lifetimes Matter

Lifetimes allow Rust to:

  • Prevent dangling references
  • Guarantee memory safety
  • Eliminate runtime memory checks
  • Enable safe concurrency

📝 Practice Exercises


Exercise 1

Write a function that returns the longer of two string slices.

Exercise 2

Create a struct that holds a reference and annotate its lifetime.

Exercise 3

Identify why returning a reference to a local variable fails.

Exercise 4

Use lifetime elision in a function.


✅ Practice Answers


Answer 1

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

Answer 2

struct Item<'a> {
    name: &'a str,
}

Answer 3

// Local variables are dropped at end of scope

Answer 4

fn len(s: &str) -> usize {
    s.len()
}

What’s Next?

Now that you understand lifetimes, the next lesson will introduce structs, which allow you to create custom data types in Rust.