Explore key concepts of Rust's ownership model, borrowing mechanisms, and lifetime annotations with this engaging quiz. Strengthen your understanding of safe memory management in Rust while testing your knowledge of borrowing rules, mutability, references, and how lifetimes prevent bugs.
What happens when a variable in Rust is assigned to another variable, such as 'let y = x;' for a non-Copy type like String?
Explanation: In Rust, assigning a non-Copy type like String to another variable transfers, or moves, ownership to the new variable, making the original variable invalid. The variables cannot both use the value; doing so causes a compilation error. Automatic cloning does not occur on simple assignment unless explicitly called. Rust does not reset the value to a default; it simply transfers ownership.
Which syntax correctly borrows a variable 'data' immutably in Rust?
Explanation: The ampersand 'u0026' before a variable creates an immutable reference, which is called borrowing in Rust. Using '*data' attempts to dereference, while 'datau0026' is invalid syntax. 'u0026u0026data' makes a reference to a reference, which is not the basic borrowing pattern. Therefore, 'u0026data' is the correct choice.
What restriction does Rust enforce when a variable has been mutably borrowed (e.g., let m = u0026mut num;)?
Explanation: Rust ensures safe memory access by allowing only one mutable reference, and no other references, to a value at any moment. Allowing only immutable references excludes having a mutable reference at the same time. Multiple mutable references simultaneously are forbidden because they risk data races. The variable does not become unusable forever; access resumes after the borrow ends.
Why does Rust's borrow checker exist in the compilation process?
Explanation: The borrow checker is a compile-time feature that checks reference rules to avoid issues like data races and dangling references. It does not generate or execute code for memory allocation. Its role is not to decrease readability; rather, it helps ensure code safety. Rust does not use a background garbage collector.
Which of the following is the correct way to annotate a lifetime for a reference parameter in a Rust function?
Explanation: The lifetime annotation must appear after the function name in angle brackets, and each reference type using the lifetime must be annotated the same way. The other options mix the syntax for references and lifetimes incorrectly, or place the annotation in the wrong position. Only the first option shows Rust's lifetime annotation syntax correctly.
What triggers a dangling reference error in Rust code?
Explanation: A dangling reference occurs when a reference points to memory that is no longer valid, such as returning a reference to a local variable inside a function. Declaring an uninitialized variable is a different type of error, not a dangling reference. Using the wrong data type results in a type error, while recursion does not cause dangling references by itself.
Which type below implements the Copy trait, so assignment does not move ownership?
Explanation: Primitive types like i32 implement the Copy trait, meaning their values are duplicated safely on assignment rather than moved. Complex types like String, Vecu003Ci32u003E, and Boxu003Ci32u003E do not implement Copy by default, as their data is allocated on the heap and requires explicit cloning for duplication. Only i32 is automatically duplicated.
Given 'fn takes_ownership(s: String)' in Rust, what happens to the variable passed as 's' after the function call?
Explanation: Passing a String (non-Copy type) by value to a function transfers ownership to the parameter inside the function. Attempting to use the original variable afterward will result in a compile-time error. There is no implicit copying or conversion to a reference unless explicitly stated. Automatic copying only happens with types that implement Copy.
When is it safe to return a reference from a function in Rust?
Explanation: Rust ensures reference safety by requiring that referenced values outlive any references returned. It is a mistake to assume primitives can be referenced without considering lifetimes. Returning references to global variables is allowed but is not a universal rule for safety. Marking a function as 'unsafe' does not bypass lifetime checks for safe code.
Which statement is true about having multiple references to a value in Rust?
Explanation: Rust's borrowing rules allow any number of immutable references, or one mutable reference, but never both at the same time. Limiting to a single reference of any kind is too strict and incorrect. Allowing simultaneous mutable and immutable references is unsafe and disallowed. Lifetime annotations for immutable references are often inferred and not always required.