Bird
Raised Fist0
Rustprogramming~20 mins

Lifetime annotations in Rust - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
Rust Lifetime Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
What is the output of this Rust code with lifetime annotations?
Consider the following Rust code snippet. What will it print when run?
Rust
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

fn main() {
    let string1 = String::from("apple");
    let string2 = "banana";
    let result = longest(string1.as_str(), string2);
    println!("{}", result);
}
Aapple
BCompilation error due to lifetime mismatch
Capplebanana
Dbanana
Attempts:
2 left
💡 Hint
Look at which string slice is longer and how lifetimes are used to ensure safety.
❓ Predict Output
intermediate
2:00remaining
What error does this Rust code produce?
Analyze the following Rust code. What error will the compiler produce?
Rust
fn invalid_ref<'a>() -> &'a str {
    let s = String::from("hello");
    &s
}

fn main() {
    let r = invalid_ref();
    println!("{}", r);
}
Aerror: `s` does not live long enough
Berror: missing lifetime specifier
Cerror: cannot return value referencing local variable `s`
DNo error, prints "hello"
Attempts:
2 left
💡 Hint
Think about the lifetime of local variables and returned references.
🔧 Debug
advanced
2:00remaining
Does this Rust code compile and what does it print?
Examine the code below. What is the correct outcome?
Rust
fn choose_first<'a>(x: &'a str, y: &str) -> &'a str {
    x
}

fn main() {
    let s1 = String::from("hello");
    let result;
    {
        let s2 = String::from("world");
        result = choose_first(s1.as_str(), s2.as_str());
    }
    println!("{}", result);
}
ACompilation error because `choose_first` has mismatched lifetimes
BNo compilation error, prints "hello"
CCompilation error because `result` has an invalid lifetime
DCompilation error because `s2` does not live long enough
Attempts:
2 left
💡 Hint
The function always returns `x`, and `y` is unused in the return value. Check if the borrow checker allows `s2` to be dropped early.
📝 Syntax
advanced
2:00remaining
Which option correctly declares a function with lifetime annotations?
Choose the correct Rust function signature that returns a reference with a lifetime tied to the input reference.
Afn get_str<'a>(s: &'a str) -> &'a str
Bfn get_str(s: &str) -> &str<'a>
Cfn get_str(s: &'a str) -> &'a str
Dfn get_str<'a>(s: &str) -> &'a str
Attempts:
2 left
💡 Hint
Remember the syntax for lifetime parameters in function signatures.
🚀 Application
expert
2:00remaining
How many items are in the resulting vector after this Rust code runs?
Given the following Rust code using lifetime annotations, how many elements does the vector `results` contain after execution?
Rust
fn collect_refs<'a>(inputs: Vec<&'a str>) -> Vec<&'a str> {
    let mut results = Vec::new();
    for s in inputs {
        results.push(s);
    }
    results
}

fn main() {
    let s1 = String::from("one");
    let s2 = String::from("two");
    let s3 = String::from("three");
    let inputs = vec![s1.as_str(), s2.as_str(), s3.as_str()];
    let results = collect_refs(inputs);
    println!("{}", results.len());
}
A3
B1
CCompilation error due to lifetime mismatch
D0
Attempts:
2 left
💡 Hint
Consider the lifetimes of the strings and the references collected.

Practice

(1/5)
1. What is the main purpose of lifetime annotations in Rust?
easy
A. To tell Rust how long references are valid
B. To specify variable types explicitly
C. To manage memory allocation manually
D. To define function return types only

Solution

  1. Step 1: Understand lifetime annotations role

    Lifetime annotations tell Rust the scope of references to avoid dangling pointers.
  2. Step 2: Compare with other options

    Other options describe unrelated concepts like type specification or memory management.
  3. Final Answer:

    To tell Rust how long references are valid -> Option A
  4. Quick Check:

    Lifetime annotations = reference validity [OK]
Hint: Lifetime annotations connect reference scopes [OK]
Common Mistakes:
  • Confusing lifetimes with types
  • Thinking lifetimes manage memory directly
  • Assuming lifetimes only affect return types
2. Which of the following is the correct syntax to declare a lifetime parameter named 'a in a function signature?
easy
A. fn example(input: &'a str) -> str<'a>
B. fn example<'a>(input: &'a str) -> &'a str
C. fn example<'a>(input: &str<'a>) -> &str
D. fn example(a: &str) -> &str<'a>

Solution

  1. Step 1: Identify correct lifetime syntax

    Lifetime parameters are declared with apostrophe before the name in angle brackets: 'a and used in references.
  2. Step 2: Check each option

    fn example<'a>(input: &'a str) -> &'a str correctly declares 'a and uses it for input and output references. Others misuse syntax or place lifetime incorrectly.
  3. Final Answer:

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

    Lifetime syntax = fn example<'a>(input: &'a str) [OK]
Hint: Declare lifetimes in angle brackets before parameters [OK]
Common Mistakes:
  • Placing lifetime after type instead of before
  • Omitting lifetime declaration in angle brackets
  • Using lifetime on non-reference types
3. What will be the output of this Rust code?
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() { x } else { y }
}

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

Solution

  1. Step 1: Understand function longest behavior

    The function returns the longer string slice between x and y.
  2. Step 2: Compare string lengths

    "apple" has 5 letters, "banana" has 6 letters, so "banana" is longer and returned.
  3. Final Answer:

    banana -> Option D
  4. Quick Check:

    Longest string = banana [OK]
Hint: Compare lengths to find longest string [OK]
Common Mistakes:
  • Assuming compilation error due to lifetimes
  • Confusing which string is longer
  • Expecting runtime error from references
4. Identify the error in this Rust code snippet involving lifetimes:
fn first_word<'a>(s: &str) -> &'a str {
    let bytes = s.as_bytes();
    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }
    &s[..]
}
medium
A. Missing lifetime annotation on parameter s
B. Cannot return a slice of s without cloning
C. Return type lifetime 'a does not match input lifetime
D. Function should return String, not &str

Solution

  1. Step 1: Check lifetime annotations on parameters and return

    The parameter s has no lifetime annotation, so Rust assigns an implicit lifetime. The return type has explicit lifetime 'a which is unrelated.
  2. Step 2: Understand lifetime mismatch

    The return lifetime 'a must be tied to the input lifetime to ensure safety. Here, 'a is unrelated, causing a mismatch error.
  3. Final Answer:

    Return type lifetime 'a does not match input lifetime -> Option C
  4. Quick Check:

    Return lifetime must match input lifetime [OK]
Hint: Return lifetime must match input reference lifetime [OK]
Common Mistakes:
  • Forgetting to add lifetime to input parameter
  • Assuming cloning is needed for slices
  • Confusing &str and String return types
5. Given two string slices with different lifetimes, how can you write a function that returns the longer slice safely using lifetime annotations? Choose the correct function signature.
hard
A. fn longest<'a>(x: &'a str, y: &'a str) -> &'a str
B. fn longest<'a, 'b>(x: &'a str, y: &'b str) -> &'a str
C. fn longest<'a, 'b>(x: &'a str, y: &'b str) -> &'b str
D. fn longest(x: &str, y: &str) -> &str

Solution

  1. Step 1: Understand lifetime requirements for return

    The returned reference must be valid as long as both inputs. Using a single lifetime 'a for both inputs and output ensures this.
  2. Step 2: Analyze options

    fn longest<'a>(x: &'a str, y: &'a str) -> &'a str uses one lifetime parameter for both inputs and output, guaranteeing safety. fn longest<'a, 'b>(x: &'a str, y: &'b str) -> &'a str and C use different lifetimes, which can cause unsafe returns. fn longest(x: &str, y: &str) -> &str omits lifetimes, causing errors.
  3. Final Answer:

    fn longest<'a>(x: &'a str, y: &'a str) -> &'a str -> Option A
  4. Quick Check:

    Single lifetime for inputs and output [OK]
Hint: Use one lifetime for all references to ensure safety [OK]
Common Mistakes:
  • Using different lifetimes for inputs and output
  • Omitting lifetime annotations causing errors
  • Assuming &str without lifetimes is enough
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