Bird
Raised Fist0
Rustprogramming~30 mins

Lifetimes in functions in Rust - Mini Project: Build & Apply

Choose your learning style10 modes available
Understanding Lifetimes in Functions
📖 Scenario: Imagine you are writing a program that manages book titles in a library. You want to write a function that takes two book title references and returns the title that comes first alphabetically. To do this safely in Rust, you need to understand how lifetimes work in functions.
🎯 Goal: Build a Rust function that takes two string slice references with lifetimes and returns the reference to the title that comes first alphabetically.
📋 What You'll Learn
Create two string slice references with exact values
Declare a lifetime parameter for the function
Write a function that returns the reference with the smaller alphabetical order
Print the result of calling the function with the two titles
💡 Why This Matters
🌍 Real World
Lifetimes are important in Rust programs that handle references to data without copying, such as managing text data or configuration settings safely.
💼 Career
Understanding lifetimes is essential for Rust developers to write safe and efficient code, especially in systems programming, web servers, and embedded software.
Progress0 / 4 steps
1
Create two book title string slices
Create two string slice variables called title1 and title2 with the exact values "Rust Programming" and "Advanced Rust" respectively.
Rust
Hint

Use let to create variables and assign string slices with double quotes.

2
Declare a lifetime parameter for the function
Write the start of a function called first_alphabetical that takes two string slice references input1 and input2 with the same lifetime 'a and returns a string slice reference with lifetime 'a. Just write the function signature line ending with an opening brace {.
Rust
Hint

Use fn function_name<'a>(param1: &'a str, param2: &'a str) -> &'a str syntax.

3
Implement the function logic to return the first alphabetical title
Inside the first_alphabetical function, write an if statement that compares input1 and input2 using <. Return input1 if it is smaller, otherwise return input2. Close the function with a closing brace }.
Rust
Hint

Use if input1 < input2 { return input1; } else { return input2; } style.

4
Call the function and print the result
Call the first_alphabetical function with title1 and title2 as arguments, store the result in a variable called first_title, and then print first_title using println!.
Rust
Hint

Use let first_title = first_alphabetical(title1, title2); and println!("{}", first_title);.

Practice

(1/5)
1. What is the main purpose of lifetimes in Rust functions?
easy
A. To control thread execution order
B. To tell Rust how long references are valid
C. To define variable types explicitly
D. To manage memory allocation size

Solution

  1. Step 1: Understand lifetimes concept

    Lifetimes specify how long references remain valid to prevent dangling pointers.
  2. Step 2: Identify purpose in functions

    Functions use lifetimes to connect input and output references safely.
  3. Final Answer:

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

    Lifetimes = reference validity [OK]
Hint: Lifetimes track reference validity duration [OK]
Common Mistakes:
  • Confusing lifetimes with memory size
  • Thinking lifetimes manage variable types
  • Assuming lifetimes control threads
2. Which of the following is the correct syntax to declare a function with a lifetime parameter 'a that returns a reference with the same lifetime?
easy
A. fn example<'a>(x: &'a str) -> &'a str { x }
B. fn example(x: &str) -> &str { x }
C. fn example<'a>(x: &str) -> &'a str { x }
D. fn example(x: &'a str) -> &str { x }

Solution

  1. Step 1: Identify lifetime parameter usage

    The lifetime 'a must be declared and used consistently in parameters and return type.
  2. Step 2: Check each option's correctness

    fn example<'a>(x: &'a str) -> &'a str { x } correctly declares 'a and uses it for input and output references.
  3. Final Answer:

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

    Lifetime declared and used consistently [OK]
Hint: Declare and use lifetime parameter consistently [OK]
Common Mistakes:
  • Omitting lifetime declaration
  • Using lifetime only in return type
  • Using lifetime only in parameter
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 s1 = String::from("apple");
    let s2 = String::from("banana");
    let result = longest(&s1, &s2);
    println!("{}", result);
}
medium
A. Runtime error
B. apple
C. Compilation error due to lifetimes
D. banana

Solution

  1. Step 1: Understand function logic

    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.
  3. Final Answer:

    banana -> Option D
  4. Quick Check:

    Longest string = banana [OK]
Hint: Compare lengths, return longer string slice [OK]
Common Mistakes:
  • Assuming compilation error due to lifetimes
  • Confusing which string is longer
  • Expecting runtime error
4. Identify the error in this Rust function and how to fix it:
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
}
medium
A. Missing lifetime annotation on function signature
B. Incorrect byte comparison syntax
C. Return type should be String, not &str
D. Function should take String, not &str

Solution

  1. Step 1: Analyze function signature

    The function returns a reference to a slice of the input string, so lifetimes must be connected.
  2. Step 2: Identify missing lifetime annotation

    Without lifetime 'a, Rust cannot ensure the returned reference is valid as long as input.
  3. Final Answer:

    Missing lifetime annotation on function signature -> Option A
  4. Quick Check:

    Lifetime needed for input and output references [OK]
Hint: Add lifetime to input and output references [OK]
Common Mistakes:
  • Ignoring lifetime errors
  • Changing return type unnecessarily
  • Confusing byte comparison syntax
5. Given two string slices with different lifetimes, how can you write a function that returns the longer slice without lifetime errors?
fn longest(x: &str, y: &str) -> &str {
    if x.len() > y.len() { x } else { y }
}
hard
A. Use different lifetime parameters for inputs and output
B. Return a String instead of a reference to avoid lifetimes
C. Add a single lifetime parameter 'a to both inputs and output: fn longest<'a>(x: &'a str, y: &'a str) -> &'a str
D. Remove references and pass owned Strings

Solution

  1. Step 1: Understand lifetime mismatch

    Without lifetime annotations, Rust cannot guarantee output reference lives as long as inputs.
  2. Step 2: Use a single lifetime parameter

    Declaring 'a for both inputs and output ties their lifetimes together, resolving errors.
  3. Final Answer:

    Add a single lifetime parameter 'a to both inputs and output: fn longest<'a>(x: &'a str, y: &'a str) -> &'a str -> Option C
  4. Quick Check:

    Single lifetime parameter ties input/output lifetimes [OK]
Hint: Use one lifetime parameter for all references [OK]
Common Mistakes:
  • Using different lifetimes for inputs and output
  • Returning owned String unnecessarily
  • Removing references instead of fixing lifetimes
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