Lifetimes Quiz - Languages Rust
Free practice quiz: Lifetimes (Languages Rust). 40 multiple-choice questions with answers and explanations. Play online, no sign-up needed.
This Languages Rust practice quiz has 40 multiple-choice questions on Lifetimes, and 40 of them come with an explanation. Try the 5 sample questions below (tap an option to check yourself), then play the full quiz online. No sign-up needed.
Start quiz: 40 questions, freeSample questions
In Rust, what is the primary purpose of lifetimes?
Show answer
Answer: A. To ensure that references do not outlive the data they point to.
Lifetimes are a compile-time mechanism in Rust that prevents dangling references. They ensure that a reference is always valid and points to valid data. This is crucial for memory safety.
Which of the following is NOT a valid lifetime elision rule in Rust?
Show answer
Answer: C. If there are multiple input lifetime parameters and the output lifetime cannot be determined, the output lifetime is always `'static`.
Rust's lifetime elision rules are designed to avoid ambiguity. The third option is incorrect; if the output lifetime cannot be determined from the inputs (especially with multiple inputs without a clear relationship to the output), the compiler will require explicit lifetime annotations, rather than defaulting to `'static` which might be incorrect and unsafe.
What does the following code snippet attempt to do, and what lifetime issue might arise?
Show answer
Answer: B. `let mut vec = vec![1, 2]; let r1 = &vec; let r2 = &vec[0]; vec.push(3);` The issue is that `r2` might become invalid if `vec.push(3)` causes reallocation, invalidating `r1`.
When you `push` into a `Vec` that might need to reallocate its internal buffer, all existing references to elements within that `Vec` (like `r2`) can become invalidated. Although `r1` is a reference to the `Vec` itself, the potential reallocation is the core issue that can break `r2`. Rust's borrow checker will prevent this code from compiling because the mutable borrow via `vec.push(3)` conflicts with the immutable borrow `r1` (and by extension, `r2`), but the underlying concern is the invalidation of `r2` if `push` reallocates.
Consider a function that takes a reference to a string slice and returns a reference to a character within that slice. What is the most appropriate lifetime annotation?
Show answer
Answer: A. `fn get_first_char<'a>(s: &'a str) -> Option<&'a u8>`
The function receives a string slice with lifetime `'a`. It returns a reference to a byte within that string slice. Therefore, the returned reference's lifetime must be tied to the input reference's lifetime `'a`. Using `Option<&'a u8>` correctly expresses this.
Can a struct definition itself have lifetime parameters?
Show answer
Answer: A. Yes, if the struct contains references, it must be parameterized by the lifetimes of those references.
Structs that hold references need to declare lifetime parameters to ensure memory safety. These parameters are bound to the lifetimes of the references within the struct, preventing the struct from outliving the data its references point to.
More questions in this quiz
Answers and explanations are in the full quiz.
- What does the following Rust function signature imply about the lifetime of the returned string slice?
- What is a 'dangling reference' in Rust, and how do lifetimes help prevent it?
- What is the primary meaning of the lifetime annotation `'a` in a Rust function signature like `fn foo<'a>(s: &'a str)`?
- In Rust, what does the `'static` lifetime signify?
- What is the purpose of the `impl Trait` syntax with respect to lifetimes?
- In the context of Rust structs holding references, what does it mean if a struct definition like `struct RefHolder<'a> { data: &'a str }` is used?
- What does the `'a` in `fn longest<'a>(s1: &'a str, s2: &'a str) -> &'a str` represent?
- Consider the Rust code: `struct Node { next: Option<&'a Node> }`. What is the issue with this struct definition?
- What is the main benefit of Rust's lifetime system compared to manual memory management or garbage collection?
- In a function `fn process(data: &[&'a str]) -> &'a str`, what is the inferred lifetime of the returned string slice?
- What happens if a Rust program attempts to use a reference after its lifetime has ended?
- Consider the lifetime annotation `fn foo<'a>(a: &'a i32, b: &i32) -> &'a i32`. Which input reference's lifetime is applied to the return value?
- What is the purpose of lifetime annotations on methods within `impl` blocks?
- In Rust, when is it appropriate to use explicit lifetime annotations for function parameters?
- If a function returns a reference to a local variable declared within that function, what will happen?
- What is the purpose of the `'a` in `struct StringSliceContainer<'a>` when used in conjunction with `data: &'a str`?
- In the context of Rust structs with references, what happens if a struct definition uses a reference without a lifetime parameter, like `struct BadContainer { data: &str }`?
- Which of the following Rust functions correctly uses lifetime annotations to ensure that the returned reference is valid?
- What does it mean for a lifetime to be generic in Rust, e.g., `fn foo<'a>(s: &'a str)`?
- Consider `struct Excerpt<'a> { text: &'a str }`. If we create an `Excerpt` holding a reference to a local variable that goes out of scope, what happens?
- What does the lifetime annotation on a trait method parameter, like `fn example(&self, other: &Self)`, imply?
- What is a 'non-lexical lifetime' (NLL) in Rust?
- Consider `struct Wrapper<'a> { inner: &'a mut String }`. If `wrapper.inner.push_str("hello")` is called, what lifetime constraints are at play?
- What is the key difference between `&str` and `String` regarding lifetimes?
- Which of the following scenarios would be correctly prevented by Rust's lifetime system?
- Consider the lifetime parameter in `fn process_slice<'a>(slice: &'a [i32])`. What is the minimum lifetime required for `slice`?
- What is the role of lifetime annotations in generic structs like `struct Point<T> { x: T, y: T }` if `T` can be a reference?
- What does the `&'a mut` syntax represent in Rust?
- What happens if you try to use a reference `r` after the variable it refers to has been dropped?
- What is the lifetime annotation `'a` in `fn takes_long_string<'a>(s: &'a str)`?
- In Rust, lifetimes are primarily concerned with:
- Consider `struct DataHolder<'a> { data: &'a i32 }`. If `holder1` has lifetime `'a` and `holder2` has lifetime `'b`, and `'a` is shorter than `'b`, which holder is more restrictive in its lifespan?
- In the signature `fn process_iter<'a, 'b>(iter1: &'a Iterator, iter2: &'b Iterator) -> &'a Iterator`, what is the primary implication of the lifetimes?
- What is the effect of using `#[derive(Clone)]` on a struct that contains references?
- Consider `struct Data<'a, 'b> { ref1: &'a i32, ref2: &'b i32 }`. What does this struct definition imply about its lifetime parameters?