---
title: "Rust: Ownership, Borrowing & Memory Safety"
description: "Test your knowledge of Rust fundamentals covering ownership, borrowing, lifetimes, traits, pattern matching, error handling, and memory-safe systems programming without a garbage collector."
author: "Mohammad Abu Mattar"
canonical: https://mkabumattar.com/quizzes/post/rust-fundamentals-quiz
---

# Rust: Ownership, Borrowing & Memory Safety

This quiz tests your grip on the parts of Rust that trip up newcomers and pay off later: ownership and moves, borrowing and lifetimes, traits and generics, pattern matching, error handling with `Result`, smart pointers, fearless concurrency, and the cargo workflow. Take your time, read each option carefully, and use the hint if you get stuck.

## Questions

### 1. What happens when you assign one String to another variable in Rust, like `let b = a;`?

- Both variables become valid references to the same heap data.
- The String is deep-cloned into the new variable automatically.
- Ownership moves to the new variable and the original becomes invalid.
- The compiler refuses to compile without an explicit lifetime annotation.

**Hint:** Think about Rust's single-owner rule and what happens to the original binding.

### 2. Which of these types implements `Copy`, so assignment duplicates the value instead of moving it?

- String
- Vec<i32>
- i32
- Box<i32>

**Hint:** Which option has no heap allocation behind it?

### 3. What does the `Drop` trait do?

- Marks a value as garbage for a runtime collector to clean up later.
- Runs custom cleanup code automatically when a value goes out of scope.
- Forces the borrow checker to ignore the value.
- Returns ownership back to the caller.

**Hint:** Think about what happens to a `File` when it goes out of scope.

### 4. How many mutable references to the same value can exist at the same time?

- Only one.
- Up to two.
- Unlimited, as long as they have different lifetimes.
- As many as there are matching immutable references.

**Hint:** It is the rule that lets the compiler reason about aliasing.

### 5. Can a mutable reference exist at the same time as immutable references to the same value?

- Yes, mutable references override immutable ones.
- No, mutable and immutable references are mutually exclusive in the same scope.
- Yes, but only inside an `unsafe` block.
- Yes, as long as the mutable reference is created first.

**Hint:** Think about why this rule eliminates data races.

### 6. What is the borrow checker?

- A runtime check that detects null pointers.
- A compile-time analysis that enforces ownership and borrowing rules.
- A linter that scans crates for unsafe code.
- A runtime garbage collector.

**Hint:** When does it do its work?

### 7. What does `&mut T` mean?

- A raw pointer to a mutable variable.
- A mutable, exclusive reference to a value of type T.
- A shared reference that can mutate the value.
- A boxed value of type T.

**Hint:** What does the absence of any other borrow during its lifetime guarantee?

### 8. What is the purpose of a lifetime annotation like `'a`?

- It forces the compiler to extend a value's lifetime.
- It tells the borrow checker how long a reference must remain valid.
- It marks a function as a constant expression.
- It enables garbage collection for the value.

**Hint:** What does the borrow checker need to know about references that cross function boundaries?

### 9. What does the `'static` lifetime mean?

- The reference is valid for the entire program.
- The value is allocated on the stack.
- The value is immutable.
- The compiler ignores its lifetime.

**Hint:** Think about where string literals are stored.

### 10. When can you omit lifetime annotations on function references?

- Only inside an `unsafe` block.
- Whenever the compiler can infer them from the standard elision rules.
- Always. Lifetimes are entirely optional.
- Only when the function has no parameters.

**Hint:** There are three lifetime elision rules; the most common cases all fit them.

### 11. What is a trait in Rust?

- A struct field.
- A shared interface that types can implement, similar to an interface or type class in other languages.
- A macro that generates code.
- A way to allocate memory on the heap.

**Hint:** Think interface or type class.

### 12. What does `impl Trait` mean when used as a return type?

- The function returns a heap-allocated trait object.
- The function returns some concrete type that implements the trait, without naming it.
- The function returns the trait itself.
- The function panics if the trait is not implemented.

**Hint:** It is sugar for an existential type.

### 13. What is the key difference between `dyn Trait` and `impl Trait`?

- `dyn` is faster than `impl`.
- `dyn Trait` is dynamic dispatch through a vtable; `impl Trait` is static dispatch resolved at compile time.
- They are identical aliases for the same thing.
- `dyn` requires `unsafe`.

**Hint:** One uses a vtable, the other monomorphizes.

### 14. What does `#[derive(Debug)]` do?

- Enables `assert!` for the type.
- Auto-generates an implementation of the `Debug` trait so you can format with `{:?}`.
- Marks the type for the borrow checker.
- Makes the type implement `Drop`.

**Hint:** What does the `{:?}` format specifier require?

### 15. What does "exhaustiveness" mean in a `match` expression?

- Every arm must include a guard clause.
- The match must cover every possible value of the scrutinee, often by using `_` for the rest.
- Every arm must return the same value.
- The match cannot also use `if let`.

**Hint:** What guarantee does it give you when you add a new enum variant later?

### 16. When would you reach for `if let` instead of `match`?

- When you need to handle only one specific pattern and ignore everything else.
- When you want exhaustive case coverage.
- When you need a return value.
- It is deprecated; you should always use `match`.

**Hint:** Think readability for the single-pattern case.

### 17. What does the `_` pattern do inside `match`?

- It forces a panic.
- It matches anything and binds it to a variable named `_`.
- It matches any value without binding it, acting as a catch-all.
- It skips the current loop iteration.

**Hint:** The key word is "wildcard".

### 18. What is the `Result<T, E>` type?

- A type that always panics on error.
- An enum with `Ok(T)` for success and `Err(E)` for failure.
- A C-style errno value.
- A trait for fallible operations.

**Hint:** It is one of the two-variant enums you use every day.

### 19. What does the `?` operator do?

- It throws a panic immediately.
- It returns early from the function on an `Err` (or `None`), propagating the value to the caller.
- It marks the expression as unsafe.
- It coerces a value into `Option::Some`.

**Hint:** What does it do on the `Err` branch?

### 20. When should you `panic!` instead of returning a `Result`?

- For any recoverable error.
- For programmer bugs and unrecoverable states. `Result` is preferred for expected failures.
- Always. `panic!` is faster than handling errors.
- Whenever the function returns an `Option`.

**Hint:** Think about whether the error represents a bug or an expected outcome.

### 21. What does `Box<T>` do?

- Allocates a value on the stack.
- Allocates a value on the heap with a single owner.
- Provides shared, mutable access across threads.
- Skips the borrow checker.

**Hint:** Heap allocation, single owner.

### 22. What is the difference between `Rc<T>` and `Arc<T>`?

- Arc is for arrays, Rc is for single values.
- `Rc` is single-threaded reference counting; `Arc` uses atomic counters and is safe across threads.
- They are aliases for the same type.
- `Rc` is heap-allocated, `Arc` is stack-allocated.

**Hint:** What does the "A" in Arc stand for?

### 23. What does `RefCell<T>` enable?

- Compile-time mutability checks.
- Interior mutability with runtime borrow checking that can panic on violation.
- Garbage collection.
- Cross-thread mutation.

**Hint:** It moves a compile-time rule to runtime.

### 24. What do the `Send` and `Sync` marker traits mean?

- `Send` types can be transferred across thread boundaries; `Sync` types can be safely shared between threads via references.
- They are deprecated traits from early Rust.
- They enable network sending and synchronization protocols.
- They are macros that generate threading code.

**Hint:** One is about transfer, the other is about sharing.

### 25. What's the recommended primitive in `std` for passing messages between threads?

- A `Mutex`.
- A channel from `std::sync::mpsc`.
- A raw `*mut T` pointer.
- `RefCell`.

**Hint:** mpsc is in the standard library for exactly this.

### 26. Why is Rust's concurrency model called "fearless concurrency"?

- The compiler eliminates all locking automatically.
- The ownership system and `Send`/`Sync` traits catch data races and many concurrency bugs at compile time.
- Rust does not actually support concurrency.
- Threads cannot crash a Rust program.

**Hint:** What does the compiler prove for you?

### 27. What is `cargo`?

- A test runner only.
- Rust's package manager and build tool. It also runs tests, builds docs, and publishes crates.
- A linter for Rust code.
- A virtual machine for Rust programs.

**Hint:** Think build + dependencies + everything in between.

### 28. What is `Cargo.toml`?

- A configuration file declaring a package's metadata, dependencies, and build settings.
- A Rust source file.
- A binary artifact produced by the compiler.
- A lockfile that pins exact dependency versions.

**Hint:** It is the package's declaration; another file is the lockfile.
