Bird
Raised Fist0
Rustprogramming~10 mins

Slice lifetime basics in Rust - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Slice lifetime basics
Create data (e.g., array)
↓
Create slice referencing data
↓
Use slice within lifetime
↓
Slice lifetime ends when data goes out of scope
↓
No dangling references allowed
This flow shows how a slice references data and must not outlive the data it points to, ensuring safe memory access.
Execution Sample
Rust
fn main() {
    let arr = [1, 2, 3];
    let slice = &arr[0..2];
    println!("{:?}", slice);
}
This code creates an array, then a slice referencing part of it, and prints the slice.
Execution Table
StepActionVariableValueNote
1Create arrayarr[1, 2, 3]Array stored on stack
2Create slice referencing arr[0..2]slice&[1, 2]Slice borrows part of arr
3Print sliceoutput[1, 2]Slice contents printed
4End of mainarr, sliceDroppedVariables go out of scope, memory freed
💡 Program ends, all variables go out of scope safely, no dangling references
Variable Tracker
VariableStartAfter Step 1After Step 2After Step 3Final
arruninitialized[1, 2, 3][1, 2, 3][1, 2, 3]dropped
sliceuninitializeduninitialized&[1, 2]&[1, 2]dropped
Key Moments - 2 Insights
Why can't the slice outlive the array it references?
Because the slice points to the array's memory, if the array is dropped first, the slice would point to invalid memory. The execution_table shows slice is created after arr and both are dropped together at the end.
What happens if we try to use the slice after arr is dropped?
Rust prevents this at compile time to avoid unsafe memory access. The execution_table's final step shows both go out of scope together, ensuring safety.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what is the value of 'slice' after Step 2?
A[1, 2]
B&[2, 3]
C&[1, 2]
Duninitialized
💡 Hint
Check the 'Value' column for 'slice' at Step 2 in the execution_table.
At which step do both 'arr' and 'slice' go out of scope?
AStep 3
BStep 4
CStep 2
DNever
💡 Hint
Look at the 'Note' column in Step 4 of the execution_table.
If we tried to use 'slice' after Step 4, what would happen?
ARust would prevent compilation due to lifetime error
BIt would print the slice normally
CIt would cause a runtime error
DThe slice would contain garbage values
💡 Hint
Refer to the key_moments section explaining Rust's safety checks on lifetimes.
Concept Snapshot
Slice lifetime basics in Rust:
- A slice references part of data (like an array).
- Slice must not outlive the data it points to.
- Rust enforces this at compile time.
- Using a slice after data is dropped is forbidden.
- This ensures safe memory access without dangling pointers.
Full Transcript
This visual execution trace shows how Rust slices work with lifetimes. First, an array 'arr' is created with values [1, 2, 3]. Then a slice 'slice' is created referencing the first two elements of 'arr'. The slice borrows part of the array's memory. When the slice is printed, it shows [1, 2]. At the end of the main function, both 'arr' and 'slice' go out of scope and are dropped safely. Rust ensures the slice cannot outlive the array it references, preventing unsafe memory access. If we tried to use the slice after the array is dropped, Rust would prevent compilation. This trace helps beginners see how slice lifetimes keep programs safe.

Practice

(1/5)
1. What does a slice lifetime in Rust indicate?
fn example<'a>(slice: &'a [i32]) {}
easy
A. How long the slice reference is valid in the program
B. The size of the slice in memory
C. The number of elements in the slice
D. The type of elements inside the slice

Solution

  1. Step 1: Understand what a lifetime means in Rust

    Lifetimes tell Rust how long a reference is valid to prevent using invalid data.
  2. Step 2: Apply this to a slice reference

    The lifetime on a slice reference means how long the slice can be safely used.
  3. Final Answer:

    How long the slice reference is valid in the program -> Option A
  4. Quick Check:

    Slice lifetime = reference validity [OK]
Hint: Lifetimes track reference validity duration [OK]
Common Mistakes:
  • Confusing lifetime with size or length
  • Thinking lifetime is about element type
  • Ignoring lifetime annotations on references
2. Which of the following is the correct syntax to declare a function that takes a slice with a lifetime parameter?
fn process_slice(____) {}
easy
A. &'a [i32]
B. &'a [i32];
C. &[i32]
D. &[i32]'a

Solution

  1. Step 1: Recall lifetime syntax for references

    Lifetimes are written as &'a before the type to indicate the lifetime of the reference.
  2. Step 2: Check each option

    &'a [i32] correctly places &'a before the slice type [i32]. &[i32] misses lifetime, &'a [i32]; has an extra semicolon, &[i32]'a places lifetime incorrectly.
  3. Final Answer:

    &'a [i32] -> Option A
  4. Quick Check:

    Lifetime syntax = &'a [type] [OK]
Hint: Lifetimes go right after & before type [OK]
Common Mistakes:
  • Putting lifetime after the type
  • Adding extra semicolons inside parameters
  • Omitting lifetime when needed
3. What will be the output of this Rust code?
fn get_first<'a>(slice: &'a [i32]) -> &'a i32 {
    &slice[0]
}

fn main() {
    let numbers = vec![10, 20, 30];
    let first = get_first(&numbers);
    println!("{}", first);
}
medium
A. 20
B. 10
C. Compilation error due to lifetime mismatch
D. Runtime panic

Solution

  1. Step 1: Understand the function behavior

    The function returns a reference to the first element of the slice, which is 10.
  2. Step 2: Check lifetime correctness and usage

    The lifetime 'a ensures the returned reference is valid as long as the input slice is valid. The vector lives long enough, so no error.
  3. Final Answer:

    10 -> Option B
  4. Quick Check:

    Returned first element = 10 [OK]
Hint: Returned slice element matches first index [OK]
Common Mistakes:
  • Thinking lifetime causes compile error here
  • Confusing element values
  • Expecting runtime panic without reason
4. Identify the error in this Rust code snippet:
fn invalid<'a>() -> &'a [i32] {
    let data = vec![1, 2, 3];
    &data[..]
}
medium
A. Missing lifetime annotation on data
B. Syntax error in slice syntax
C. The function returns a reference to data that will be dropped
D. No error, code is correct

Solution

  1. Step 1: Analyze the function return and data lifetime

    The function returns a slice reference with lifetime 'a, but data is created inside the function and dropped when it ends.
  2. Step 2: Understand why this causes an error

    Returning a reference to local data is invalid because the data won't live long enough, causing a dangling reference.
  3. Final Answer:

    The function returns a reference to data that will be dropped -> Option C
  4. Quick Check:

    Returning local reference = error [OK]
Hint: Never return reference to local variable [OK]
Common Mistakes:
  • Assuming lifetime annotation fixes local data drop
  • Ignoring ownership rules
  • Thinking slice syntax is wrong
5. Given this function that returns a slice from two input slices, which lifetime annotation is correct to ensure safety?
fn longest_slice<'a>(x: &'a [i32], y: &'a [i32]) -> &____ [i32] {
    if x.len() > y.len() { x } else { y }
}
hard
A. 'a + 'b
B. 'b
C. 'static
D. 'a

Solution

  1. Step 1: Understand the function's return lifetime

    The function returns a slice that could come from either input slice, both sharing lifetime 'a.
  2. Step 2: Use shared lifetime for safety

    The correct lifetime for the return is 'a, matching the lifetime of both input slices.
  3. Final Answer:

    'a -> Option D
  4. Quick Check:

    Return lifetime = 'a of inputs [OK]
Hint: Return lifetime must cover both inputs [OK]
Common Mistakes:
  • Choosing only one input lifetime
  • Using 'static without reason
  • Ignoring lifetime intersection rules
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