Bird
Raised Fist0
Rustprogramming~30 mins

Why lifetimes exist in Rust - See It in Action

Choose your learning style10 modes available
Why lifetimes exist
📖 Scenario: Imagine you are writing a program that stores references to parts of a string. You want to make sure these references are always valid while your program runs.
🎯 Goal: Learn why Rust uses lifetimes to keep track of how long references are valid and avoid errors.
📋 What You'll Learn
Create a string variable called text with the value "Hello, Rust!"
Create a reference variable called first_word that points to the first 5 characters of text
Add a lifetime annotation to a function called get_first_word that returns a string slice referencing text
Print the value of first_word to show the result
💡 Why This Matters
🌍 Real World
Lifetimes help Rust programs avoid bugs related to invalid references, which is important in systems programming and safe memory management.
💼 Career
Understanding lifetimes is essential for Rust developers working on performance-critical or safe software, such as embedded systems, web servers, or game engines.
Progress0 / 4 steps
1
Create the initial string variable
Create a variable called text and set it to the string "Hello, Rust!"
Rust
Hint

Use let to create a variable and assign the string value.

2
Create a reference to the first word
Create a variable called first_word that is a string slice referencing the first 5 characters of text
Rust
Hint

Use &text[0..5] to get a slice of the first 5 characters.

3
Add a function with lifetime annotation
Write a function called get_first_word that takes a string slice s with a lifetime 'a and returns a string slice with the same lifetime 'a. Inside, return the first 5 characters of s
Rust
Hint

Use &'a str for the input and output types and return the slice inside the function.

4
Print the result
Call the function get_first_word with text and assign the result to first_word. Then print first_word using println!
Rust
Hint

Use let first_word = get_first_word(text); and then println!("{}", first_word);

Practice

(1/5)
1.

Why does Rust use lifetimes like 'a in its code?

easy
A. To automatically free memory like a garbage collector
B. To make the code run faster by skipping checks
C. To allow multiple mutable references at the same time
D. To ensure references do not outlive the data they point to

Solution

  1. Step 1: Understand what lifetimes represent

    Lifetimes in Rust show how long a reference is valid to prevent dangling references.
  2. Step 2: Connect lifetimes to safety

    They ensure references do not outlive the data they point to, avoiding bugs.
  3. Final Answer:

    To ensure references do not outlive the data they point to -> Option D
  4. Quick Check:

    Lifetimes = prevent dangling references [OK]
Hint: Lifetimes prevent references to missing data [OK]
Common Mistakes:
  • Thinking lifetimes speed up code
  • Confusing lifetimes with garbage collection
  • Believing lifetimes allow multiple mutable references
2.

Which of the following is the correct way to declare a function with a lifetime parameter 'a for a reference argument in Rust?

fn example(____ s: &'a str) -> &'a str { s }
easy
A. fn example<'a>(s: &'a str) -> &'a str
B. fn example(s: &str<'a>) -> &str<'a>
C. fn example(s: &'a str) -> &str
D. fn example<'a>(s: &str) -> &'a str

Solution

  1. Step 1: Recall lifetime syntax in function signatures

    Lifetimes are declared before the function name with 'a and used on references.
  2. Step 2: Match correct syntax

    fn example<'a>(s: &'a str) -> &'a str correctly declares 'a and uses it on both input and output references.
  3. Final Answer:

    fn example<'a>(s: &'a str) -> &'a str -> Option A
  4. Quick Check:

    Lifetime syntax = fn example<'a>(s: &'a str) -> &'a str [OK]
Hint: Declare lifetime before fn name and use on references [OK]
Common Mistakes:
  • Putting lifetime after & instead of before type
  • Forgetting to declare lifetime before function name
  • Using lifetime on non-reference types
3.

What will this Rust code print?

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

fn main() {
    let s1 = String::from("apple");
    let s2 = "banana";
    let result = longest(&s1, s2);
    println!("{}", result);
}
medium
A. apple
B. banana
C. Compilation error due to lifetimes
D. Runtime error due to invalid reference

Solution

  1. Step 1: Understand function longest behavior

    It returns the longer string slice between x and y.
  2. Step 2: Compare lengths of "apple" and "banana"

    "apple" has 5 letters, "banana" has 6, so it returns "banana".
  3. Final Answer:

    banana -> Option B
  4. Quick Check:

    Longest string = banana [OK]
Hint: Compare string lengths carefully to find longest [OK]
Common Mistakes:
  • Assuming s1 is longer without counting
  • Thinking lifetimes cause compile error here
  • Confusing references with ownership causing runtime error
4.

Identify the error in this Rust code related to lifetimes:

fn first_word(s: &str) -> &str {
    let bytes = s.as_bytes();
    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }
    &s
}

fn main() {
    let word;
    {
        let s = String::from("hello world");
        word = first_word(&s);
    }
    println!("{}", word);
}
medium
A. Error: cannot borrow s as mutable
B. Error: missing lifetime annotation in function signature
C. Error: returned reference may outlive borrowed data
D. No error, code runs fine

Solution

  1. Step 1: Analyze lifetime of variable s

    Variable s is created inside inner block and dropped after it ends.
  2. Step 2: Check lifetime of returned reference word

    word holds reference to s, but s is dropped before println!, causing dangling reference.
  3. Final Answer:

    Error: returned reference may outlive borrowed data -> Option C
  4. Quick Check:

    Dangling reference error = Error: returned reference may outlive borrowed data [OK]
Hint: References must not outlive their data scope [OK]
Common Mistakes:
  • Ignoring scope of s and thinking code is safe
  • Assuming missing lifetime annotation causes error here
  • Confusing mutable borrow errors with lifetime errors
5.

You want to write a function that returns a reference to the longer string slice between two inputs, but one input is owned String and the other is a string slice &str. How should you use lifetimes to make this safe and correct?

hard
A. Convert the owned String to a slice and use a single lifetime for both inputs and output
B. Return the owned String directly without lifetimes
C. Use different lifetimes for each input and output to avoid conflicts
D. Clone both inputs and return an owned String without references

Solution

  1. Step 1: Understand input types and lifetimes

    Owned String must be converted to a string slice (&str) to use lifetimes uniformly.
  2. Step 2: Use one lifetime parameter for both inputs and output

    This ensures the returned reference is valid as long as both inputs are valid.
  3. Final Answer:

    Convert the owned String to a slice and use a single lifetime for both inputs and output -> Option A
  4. Quick Check:

    Single lifetime with slices = Convert the owned String to a slice and use a single lifetime for both inputs and output [OK]
Hint: Use &str slices and one lifetime for safe references [OK]
Common Mistakes:
  • Returning owned String without references when references expected
  • Using multiple lifetimes causing borrow conflicts
  • Forgetting to convert String to &str before comparison
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard