Top 30 Intermediate Go & Rust Concepts Quiz
30 intermediate multiple-choice Go & Rust concept questions, the mechanics underneath the basics: how the pieces relate and where the usual mental model stops holding. They come from 30 bites in the Go & Rust library, the middle slice of the 144 Go & Rust concept questions in the library. Answer them here or read straight down. Every question carries the correct option, why it is correct, and a link to the bite it came from.
Go web services, Rust backends, systems programming
30 questions. Pick an answer, or open “Show the answer” to read it.
Answers are graded in your browser. Nothing is saved, and no XP or streak is earned here. The app keeps score.
Question 1 of 30
What is the immediate consequence when ownership of a variable is moved to a function in Rust?
Show the answer
Answer: a · The original variable becomes invalid and cannot be accessed further.
When ownership is moved, the original variable is invalidated, as the card states 'Once you've given it away, it's no longer yours to use' and the example demonstrates a compile error for subsequent use. Option D is incorrect because for complex types like String, ownership is moved, not copied, unless explicitly cloned. Option B is incorrect because the memory is freed when the new owner (the function's parameter) goes out of scope, not immediately upon the move.
Read the full bite: Rust Ownership: Memory Safety Without a Garbage Collector
Question 2 of 30
Which scenario correctly describes a fundamental rule enforced by Rust's borrow checker for memory safety?
Show the answer
Answer: a · You can have either one mutable reference or any number of immutable references to data, but not both simultaneously.
The borrow checker enforces that you can have either one mutable reference OR multiple immutable references to a piece of data at any given time, but never both, preventing data races. Option D is incorrect because the borrow checker strictly disallows multiple mutable references to the same data concurrently, regardless of the function scope.
Read the full bite: Rust's Borrow Checker: Memory Safety at Compile Time
Question 3 of 30
What is the primary benefit of defining a Rust trait, such as Summary with a summarize method, and implementing it for multiple distinct types?
Show the answer
Answer: b · It allows writing generic functions that can operate on any type that fulfills the Summary contract, promoting code reuse.
The card states traits enable "writing generic functions that can accept any type that fulfills a certain contract," which directly leads to code reuse and abstraction. Option D is a tempting distractor because traits can have default implementations, but the primary benefit isn't the automatic provision of a default, but rather the ability to treat different types uniformly based on their shared behavior.
Question 4 of 30
What is the primary benefit of Go's garbage collector for concurrent network services?
Show the answer
Answer: c · It performs most of its work concurrently with the application, ensuring high responsiveness.
Go's GC is designed to run concurrently with the application, minimizing the duration of "stop-the-world" pauses to maintain responsiveness for services. While pauses are very short, they are not completely eliminated, making option A incorrect.
Read the full bite: Go's Garbage Collector: The Concurrent Cleaner
Question 5 of 30
When a Rust function attempts to parse user input that might be malformed, which error handling approach is most appropriate?
Show the answer
Answer: b · Returning a Result<T, E> enum, allowing the caller to handle the potential parsing failure gracefully.
The card specifies that Result<T, E> should be used for expected failures like parsing user input, which are conditions outside the program's direct control. panic! is reserved for unrecoverable programmer bugs, not anticipated external data issues.
Read the full bite: Rust's Two Error Types: Recoverable vs. Unrecoverable
Question 6 of 30
Why is the Last-In, First-Out (LIFO) execution order of Go's `defer` statements considered crucial for resource management?
Show the answer
Answer: d · It correctly handles dependencies, like unlocking a mutex that protects a resource before closing that resource.
The card explains that LIFO is crucial because it naturally handles nested cleanup, giving the example: "if you open a file and then lock a mutex, you'll want to unlock the mutex first, then close the file. defer handles this naturally." Option C is a true statement about LIFO, but B explains the *benefit* of that order in resource management. Option B is a general benefit of `defer`, not specific to its LIFO order. Option A describes a scenario where `defer` should be avoided, as it can cause memory leaks in loops.
Question 7 of 30
Which scenario best justifies using a pointer in Go?
Show the answer
Answer: c · Passing a large data structure to a function to prevent expensive copying.
The card states that a key reason to use pointers is "when you are passing a large struct to a function and want to avoid the performance overhead of making a copy." Option A describes pass-by-value behavior, which is the opposite of using a pointer to share or modify the original data.
Question 8 of 30
What is the fundamental difference between variable shadowing and variable mutation in Rust?
Show the answer
Answer: d · Shadowing declares a new variable that makes the previous one inaccessible, while mutation modifies the value of an existing variable in place.
Shadowing creates a completely new variable, potentially allocating new memory, making the original inaccessible. Mutation, however, changes the value of an existing variable in its current memory location. Option B describes when to use each, not the fundamental difference in their operation.
Read the full bite: Rust's Variable Shadowing: Re-binding, Not Mutating
Question 9 of 30
What is the primary advantage of defining a function to accept `&[T]` instead of `&Vec<T>`?
Show the answer
Answer: d · It makes the function more generic, allowing it to operate on data from Vecs, arrays, or other slices.
The card states that `&[T]` makes functions more generic, allowing them to operate on data from various sources like `Vec`s, arrays, or other slices. Option A is incorrect because slices are borrowed views, not copies, and option C is incorrect because while `&[T]` is immutable, `&Vec<T>` also provides immutability; the key advantage of `&[T]` is its genericity.
Read the full bite: Rust Slices (&[T]): Views Without Ownership
Question 10 of 30
When writing a Rust function that needs to read and process string data without modifying or taking ownership, which parameter type is generally most flexible and efficient?
Show the answer
Answer: b · &str
The card explicitly states to "Use &str as function parameters whenever you only need to read string data" because it is more flexible, accepting owned Strings, string literals, and other slices without unnecessary allocations. While &String is a reference, &str is more versatile as it can directly represent string literals.
Read the full bite: Rust's Two String Types: String vs. &str
Question 11 of 30
When modeling a type that can be one of several kinds, each with different data, what is the key advantage of using a Rust enum with associated data over a struct containing a 'kind' enum and separate fields?
Show the answer
Answer: c · It guarantees that only valid data combinations for each variant can be represented, enhancing type safety.
The card emphasizes that enums with associated data prevent the creation of 'invalid states' and are 'more idiomatic and type-safe' compared to using a struct with a 'kind' field. Option B, while a characteristic of enums, is not presented as the primary advantage over the alternative data modeling approach discussed.
Read the full bite: Rust Enums: Attaching Data Directly to Variants
Question 12 of 30
To make a function `my_func` nested within `mod inner` (which is inside `mod outer`) accessible from the crate root, what visibility is required?
Show the answer
Answer: b · `my_func`, `mod inner`, and `mod outer` must all be marked `pub`.
The card states that for an item deep inside a module tree to be accessible from the outside, "it and all of its parent modules in the path must be marked pub." Therefore, all modules in the path to `my_func` must be public. Option A is a tempting distractor because it makes the immediate parent public, but misses the higher-level parent module.
Read the full bite: Rust Item Visibility: Private by Default
Question 13 of 30
In Rust, what is the key distinction between `my_instance.name()` and `my_instance.name`?
Show the answer
Answer: c · my_instance.name() calls a method, while my_instance.name accesses a field.
The card explicitly states, "The key footgun: instance.name() calls a method, but instance.name accesses a field." This highlights how Rust's syntax differentiates between invoking a method and accessing a struct field, even if they share the same identifier. Option A is incorrect because the card shows methods and fields can share names.
Read the full bite: Rust Methods: Attaching Behavior to Data
Question 14 of 30
A module resides in the cli subdirectory of a repository rooted at github.com/acme/tool. If the team releases major version 3, which module path must go.mod declare?
Show the answer
Answer: a · github.com/acme/tool/cli/v3
The card states that a module path encodes the repository root plus any subdirectory, and for major versions 2+ must end with the version suffix. Option C omits the required /v3 suffix, while Option D incorrectly places the version before the subdirectory instead of at the end of the full module path.
Question 15 of 30
What is the main reason to categorize a dependency under "dev-dependencies" in Cargo.toml?
Show the answer
Answer: b · It's for tools and crates needed for testing, examples, or benchmarks, which are not included in the final production binary.
The card states that "dev-dependencies" are for "tools used only in the kitchen, like for testing" and are "available for cargo test but is not compiled into the final production binary, keeping it lean." Option C is incorrect because dev-dependencies are used during development and testing, not exclusively tied to the release build profile.
Question 16 of 30
Given `src/lib.rs` declares `mod utils;` and `src/utils.rs` declares `pub mod helpers;`, where does Rust expect `helpers`'s code?
Show the answer
Answer: d · src/utils/helpers.rs
The module system maps recursively; `helpers` is a submodule of `utils`, so its file is expected within the `utils` directory relative to `src`. Option B is incorrect because `src/helpers.rs` would be the location if `mod helpers;` was declared directly within `src/lib.rs`, not nested within `utils`.
Question 17 of 30
What is the primary reason Rust prevents implementing the Drop trait for types that also implement Copy?
Show the answer
Answer: a · It would lead to ambiguity about which copy is responsible for cleaning up the resource.
The card states that Drop and Copy are mutually exclusive because "if a type can be trivially bit-copied, it becomes ambiguous which copy is responsible for cleaning up the resource." This prevents issues like double-freeing. While Copy types are often simple and cheap (making option B tempting), the fundamental reason for the restriction is the ambiguity of resource ownership and cleanup, not just performance.
Read the full bite: Rust's `Drop` Trait: Automatic Resource Cleanup
Question 18 of 30
What is the primary mechanism by which Rust's RAII ensures automatic resource cleanup?
Show the answer
Answer: a · Resources are automatically released when their owning variable goes out of scope, invoking its 'drop' method.
Rust's RAII ties a resource's lifetime to its owner's scope; when the owner variable goes out of scope, its 'drop' method is automatically called to clean up the resource. This mechanism is deterministic and distinct from a non-deterministic garbage collector, which option D incorrectly suggests.
Read the full bite: RAII in Rust: Automatic Cleanup via Scope
Question 19 of 30
Which function signature would require explicit lifetime annotations because Rust's lifetime elision rules cannot infer them?
Show the answer
Answer: a · fn compare_strings(a: &str, b: &str) -> &str
The function `compare_strings` takes two input references and returns one, creating an ambiguous scenario where the compiler cannot determine which input's lifetime the output should inherit, thus requiring explicit annotation. In contrast, `find_first_char` has only one input reference, allowing elision rule 2 to apply.
Read the full bite: Rust's Lifetime Elision: When You Can Skip 'a
Question 20 of 30
For systems requiring predictable performance and fine-grained resource control, what is a key benefit of Rust's ownership model compared to garbage collection?
Show the answer
Answer: b · It guarantees memory safety at compile-time, avoiding runtime overhead and unpredictable pauses.
Rust's ownership model enforces memory safety at compile-time, which eliminates the need for a runtime garbage collector and its associated overhead or unpredictable pauses. While it ensures safety, it does not fully automate memory management; instead, it provides strict compiler-enforced rules for manual memory handling, which can lead to a steeper learning curve.
Read the full bite: GC vs. Ownership: Two Paths to Memory Safety
Question 21 of 30
When adding context to an error using fmt.Errorf, what is the primary consequence of using the %v verb instead of %w?
Show the answer
Answer: d · The new error will only contain the string representation of the original error, making its underlying type uninspectable.
Using %v with fmt.Errorf converts the original error into its string representation, discarding its valuable type information. This prevents programmatic inspection of the underlying error using functions like errors.Is or errors.As. Option B is incorrect because if the type were preserved, errors.Is and errors.As would be usable.
Read the full bite: Go Error Wrapping: Preserving Context, Not Just Text
Question 22 of 30
In Rust, for which scenario is the `?` operator most effectively employed?
Show the answer
Answer: c · When chaining several fallible operations and you want to propagate any encountered error up to the calling function.
The `?` operator is specifically designed to propagate `Err` or `None` values up the call stack, making it ideal for chaining fallible operations while keeping the success path clean. It is not used for immediate, specific error handling like logging or retrying, nor is it applicable in functions that do not return a `Result` or `Option`.
Read the full bite: Rust's Question Mark Operator (?): Propagate Errors, Not Boilerplate
Question 23 of 30
When is `Result<T, E>` the most appropriate error handling mechanism in Rust?
Show the answer
Answer: a · When a function performs an I/O operation that could predictably fail, and the caller might want to handle that failure.
The card states that Result is for "expected and recoverable errors" like I/O operations, where the caller can act upon the failure. Unrecoverable programming mistakes or immediate termination typically call for panicking, not Result.
Read the full bite: Result: Handling Recoverable Errors in Rust
Question 24 of 30
What is the primary advantage of Rust's monomorphization approach for generics?
Show the answer
Answer: c · It eliminates runtime overhead by resolving all generic function calls at compile time.
Monomorphization's core benefit is to provide 'zero-cost abstractions' by generating specialized code at compile time, thus eliminating runtime overhead for generic function calls. It typically increases binary size, and heterogeneous collections require dynamic dispatch, not monomorphization.
Read the full bite: Static Dispatch: Zero-Cost Abstraction via Monomorphization
Question 25 of 30
What is the main benefit of using "impl Trait" in a function's return type, such as "-> impl Fn()", compared to "-> Box<dyn Fn() >"?
Show the answer
Answer: a · It guarantees that the returned type is known at compile time, enabling static dispatch and avoiding heap allocation.
The card states that "impl Trait" in return position avoids the performance penalty of boxing (heap allocation) and allows for static dispatch because the compiler knows the exact type. Option D describes a scenario where "Box<dyn Trait>" is still necessary, as "impl Trait" requires a single, concrete return type.
Read the full bite: Rust's `impl Trait`: Hiding Concrete Types
Question 26 of 30
What is a significant risk associated with using a buffered channel in Go?
Show the answer
Answer: b · It can mask fundamental concurrency issues, making deadlocks harder to diagnose.
The card explicitly warns against using a buffered channel to 'fix' a deadlock, stating that it 'may just hide the problem, making it intermittent and harder to debug.' Option A describes the behavior of an unbuffered channel, or a buffered channel only when its buffer is full, and does not guarantee processing, only queuing.
Question 27 of 30
In Rust's async/await model, what is the fundamental mechanism enabling cooperative concurrency?
Show the answer
Answer: c · Tasks explicitly yield control to the runtime at .await points, allowing other tasks to run.
Rust's async/await achieves cooperative concurrency because tasks explicitly yield control to the runtime using the .await keyword, allowing the runtime to switch to other tasks. This differs from preemptive multitasking (option B), where the operating system or runtime forcibly interrupts tasks.
Read the full bite: Rust's async/await: Cooperative Concurrency
Question 28 of 30
What is the primary benefit of employing an async runtime in a Rust application?
Show the answer
Answer: b · It enables efficient handling of numerous concurrent I/O-bound tasks.
An async runtime is designed to efficiently manage many concurrent I/O-bound operations, allowing a single thread to handle thousands of tasks by polling futures and switching context when I/O is pending. The card explicitly states that async offers no performance benefit for purely CPU-bound tasks and that async/await are just syntax.
Read the full bite: Rust Async Runtimes: The Engine for `async/await`
Question 29 of 30
What is the primary safety benefit of Rust's MutexGuard object?
Show the answer
Answer: d · It automatically releases the lock when the MutexGuard itself goes out of scope, preventing forgotten unlocks.
The card states that when the `MutexGuard` goes out of scope, the lock is automatically released, preventing forgotten unlocks. Option A is incorrect because the card explicitly warns against relying on mutex poisoning for soundness, as it's an advisory mechanism.
Read the full bite: Rust's `std::sync::Mutex`: Guarding Shared Data
Question 30 of 30
What is the primary benefit of using cargo add instead of manually editing the Cargo.toml file?
Show the answer
Answer: a · It ensures correct TOML syntax and automatically determines the latest compatible version for the added crate.
The card states that cargo add "automates this, ensuring correct syntax and fetching rules directly from the command line" and "prevents the manual syntax errors and version lookup." Option C is incorrect because cargo add is designed for adding/modifying dependencies for a single package, not for sweeping updates across an entire workspace.
Read the full bite: cargo add: Stop Editing Cargo.toml By Hand
Could you explain these out loud?
That is what an interview actually tests. Tezvyn gives you questions like these with what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.