Code of the Day
IntermediateOwnership in depth

Lab: Ownership in depth

Consolidate your understanding of references, slices, lifetimes, and error handling through scenario-based questions.

Lab · optionalRustIntermediate15 min
Recommended first
By the end of this lesson you will be able to:
  • Apply borrowing rules to multi-step code scenarios
  • Reason about lifetime relationships without running code
  • Trace error propagation through ? chains

This lab checks your understanding of the ownership-in-depth module through scenario questions. No compiler required — the goal is to reason about Rust's rules before you try them. When you're uncertain, make a prediction, then verify in a real project.

Part 1: Borrowing rules

Knowledge check

  1. 1.
    The following code compiles. True or false?

    let mut v = vec![1, 2, 3];
    let first = &v[0];
    v.push(4);
    println!("{}", first);
  2. 2.
    Which change would make the previous snippet compile?
  3. 3.
    What does a "fat pointer" mean in the context of a Rust slice like &[i32]?

Part 2: Lifetime scenarios

Knowledge check

  1. 1.
    Does this function need explicit lifetime annotations?

    fn greet(name: &str) -> String {
        format!("Hello, {}!", name)
    }
  2. 2.
    Which elision rule covers this signature?

    fn first(v: &[i32]) -> &i32
  3. 3.
    A struct Wrapper<'a> { val: &'a str } guarantees that Wrapper cannot be used after the &str it holds is dropped.

Part 3: Error propagation

Knowledge check

  1. 1.
    A function returns Result<String, io::Error>. Inside it, you call another function that returns Result<Vec<u8>, ParseError>. You want to use ? on both. What do you need?
  2. 2.
    What is the idiomatic return type for main() when you want to use ? inside it?
  3. 3.
    The ? operator can be used inside a closure that returns Result.

Putting it together

The three topics in this module are deeply connected. Slices are borrowed windows — their validity is tracked by lifetimes. Error handling with ? uses From conversions that involve owned types, not references. The ownership model is the common thread: every Rust feature is designed so the compiler can prove your program won't corrupt memory.

If any of these questions surprised you, revisit the corresponding lesson. The borrow checker's error messages are precise — the fastest way to build intuition is to write code that you expect to fail, read the error, and understand why it's right.

Where to go next

Next module: Types & traits — starting with enums and pattern matching, where you'll see how Result and Option are just two examples of a much richer pattern.

Finished reading? Mark it complete to track your progress.

On this page