Top 30 Advanced Go & Rust Concepts Quiz
30 advanced multiple-choice Go & Rust concept questions, the corners that separate having used it from understanding it: internals, edge cases, and the reasons behind the design. They come from 30 bites in the Go & Rust library, the hardest 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 characteristic most directly prevents an abstraction from being considered 'zero-cost'?
Show the answer
Answer: b · It necessitates runtime data or dynamic dispatch.
An abstraction is not zero-cost if it requires runtime information, such as dynamic dispatch or allocations, because the compiler cannot prove it away entirely. While many function calls (option C) might seem costly, they can often be inlined and optimized away at compile time, which is a hallmark of zero-cost abstractions.
Read the full bite: Zero-Cost Abstractions: Pay at Compile Time, Not Runtime
Question 2 of 30
What is the primary purpose of using Rust's turbofish (`::<>`) or fully qualified syntax?
Show the answer
Answer: c · To specify which trait's method to use when multiple traits define methods with the same name for a given type, or to provide type hints for generic functions.
The card states the turbofish is used to resolve ambiguity when a type implements multiple traits with same-named methods, or to provide type hints for generic functions like `collect()`. Option C accurately describes these scenarios. Option A describes defining generics, not resolving ambiguity during their use.
Read the full bite: Rust's Turbofish (`::<>`): When the Compiler Needs Help
Question 3 of 30
What is the primary reason Box<T> is essential for defining recursive data structures in Rust?
Show the answer
Answer: d · It ensures that the overall size of the recursive type can be determined at compile time.
The core problem Box<T> solves for recursive types is making their size known at compile time by storing the actual data on the heap and only keeping a fixed-size pointer on the stack. While Box<T> can help prevent stack overflows by moving data off the stack, this is a secondary effect; the primary issue for recursive types is their indeterminate size at compile time.
Read the full bite: Using Box<T> for Heap Allocation in Rust
Question 4 of 30
For which access pattern is Go's sync.Map specifically optimized?
Show the answer
Answer: c · Keys that are written once or infrequently, but read many times concurrently.
sync.Map is designed for read-heavy workloads where keys are stable and written once or infrequently, as stated in the card. It is explicitly not a general-purpose replacement for a map protected by a mutex, making option A a common but incorrect assumption.
Read the full bite: Go's sync.Map: A Specialized Concurrent Map
Question 5 of 30
Which problem does Weak<T> primarily help mitigate when used in conjunction with Rc<T>?
Show the answer
Answer: a · Preventing memory leaks caused by reference cycles.
The card states that "To prevent memory leaks from cycles, Rc<T> is often paired with Weak<T>." Option B describes the role of Arc<T>, while option C describes the role of types like RefCell<T> or Cell<T>.
Read the full bite: Rust's Rc<T>: Shared Ownership on a Single Thread
Question 6 of 30
When should Arc<T> be preferred over Rc<T> in Rust?
Show the answer
Answer: c · To enable safe sharing of data ownership between multiple threads.
Arc<T> is specifically designed for thread-safe shared ownership, allowing multiple threads to safely access the same data, unlike Rc<T> which is for single-threaded use. While shared data often needs to be mutable, Arc<T> itself only provides shared ownership, not mutability protection; a Mutex is typically combined with Arc<T> for that purpose.
Read the full bite: Rust's Arc<T>: Share Data Ownership Across Threads
Question 7 of 30
What is the primary benefit of organizing Go packages within an 'internal' directory?
Show the answer
Answer: a · It allows the package to be freely refactored or modified without affecting external module users.
The 'internal' directory's main purpose is to create a visibility barrier, allowing code within it to be refactored or changed without creating breaking changes for external modules that cannot import it. It does not prevent other packages within the same module from importing it, nor does it relate to performance optimization or documentation generation.
Read the full bite: Go's `internal` Directory: Private by Convention
Question 8 of 30
Which statement accurately describes a key characteristic of dependency management within a Rust Cargo workspace?
Show the answer
Answer: b · All member crates share a single Cargo.lock file, ensuring uniform dependency versions across the project.
A Cargo workspace unifies dependency management by providing a single Cargo.lock file for all its member crates, ensuring consistent dependency versions across the entire project. Member crates do not maintain individual lock files, nor are dependencies resolved independently.
Read the full bite: Rust Cargo Workspaces: A Monorepo Control Panel
Question 9 of 30
Which mechanism is crucial for Go's tri-color garbage collector to maintain correctness when the application concurrently modifies the object graph?
Show the answer
Answer: d · The write barrier that intercepts pointer modifications.
The write barrier is essential for concurrent correctness; it intercepts pointer modifications by the application (mutator) to ensure that if a black object points to a white object, the white object is immediately colored grey. This prevents the GC from incorrectly reclaiming a live object that the application just made reachable. The other options describe parts of the GC cycle but do not specifically address the challenge of concurrent mutations by the application.
Read the full bite: Go's GC: Low-Latency Collection with Tri-color Marking
Question 10 of 30
When is Rust's interior mutability pattern, such as using RefCell<T>, most appropriately applied?
Show the answer
Answer: c · When the compiler's static borrow checker cannot verify a valid mutation, often with immutable &self references.
The correct answer is B because interior mutability provides a controlled escape hatch for valid mutations that the conservative compile-time borrow checker cannot statically prove safe, especially when dealing with immutable references like &self. Option D is incorrect because RefCell<T> is strictly for single-threaded use; multithreaded scenarios require types like Mutex or RwLock.
Read the full bite: Rust's Interior Mutability: Mutating 'Immutable' Data
Question 11 of 30
What fundamental change does Rust's Non-Lexical Lifetimes (NLL) introduce to the borrow checker's behavior?
Show the answer
Answer: a · It permits a borrow to end based on its last actual use, rather than strictly at the end of its declared lexical scope.
NLL's core innovation is to make the borrow checker usage-based, ending a borrow after its last use, not its lexical scope, which allows for more flexible code. It does not change fundamental borrowing rules like preventing multiple mutable references, nor is it related to lifetime parameter inference or data deallocation.
Read the full bite: Rust's NLL: Smarter Borrows Based on Use, Not Scope
Question 12 of 30
Which scenario best justifies using Go's panic/recover mechanism?
Show the answer
Answer: a · To gracefully handle an unexpected nil pointer dereference in a web server request handler.
Option A describes handling an 'unexpected nil pointer dereference,' which is a catastrophic programmer error, aligning with panic/recover's purpose of containing such bugs to keep a server running. Option C, failing to validate user input, is an expected operational failure that should be handled with explicit error returns, not panic.
Read the full bite: Go's Panic/Recover: For Exceptional Errors Only
Question 13 of 30
In Rust, which scenario most appropriately warrants the use of `panic!` instead of `Result` for error handling?
Show the answer
Answer: a · A function receives an argument that violates its documented preconditions, indicating a programming bug.
Panic! is intended for unrecoverable bugs or violations of fundamental program invariants, such as a function being called with an argument that should be impossible according to its design. Expected runtime failures like network timeouts, invalid user input, or file not found errors are recoverable and should be handled using `Result`.
Read the full bite: Rust's `panic!`: When to Crash Your Program Intentionally
Question 14 of 30
For which scenario is thiserror specifically recommended in Rust?
Show the answer
Answer: a · Building a library where consumers need to programmatically differentiate between various failure modes.
The card explicitly states to "Use thiserror when writing a library where consumers need to programmatically react to different kinds of errors." Option D describes the use case for `anyhow`, which the card advises against for `thiserror`.
Read the full bite: Composable Error Types with `thiserror` in Rust
Question 15 of 30
Under which condition would you prefer using a generic type parameter on a trait over an associated type?
Show the answer
Answer: d · When a type needs to implement the trait for several distinct related types.
Associated types enforce that a type can implement a trait only once with a specific concrete type. If a type needs to implement the trait multiple times with different related types, like Rust's From<T> trait, then a generic type parameter is required. Option B is incorrect because associated types are specifically designed to reduce verbosity and simplify function signatures.
Read the full bite: Rust Associated Types: One Trait, One Concrete Type
Question 16 of 30
Which scenario best illustrates the primary function of a Rust marker trait?
Show the answer
Answer: b · Preventing a type from being shared across thread boundaries unless explicitly marked safe.
Marker traits, like Send, are empty traits that signal properties to the compiler, enabling compile-time safety checks, such as preventing unsafe data from being moved between threads. Options A, B, and D describe the function of regular traits, which define methods and behavior, contrasting with marker traits that are purely for classification.
Question 17 of 30
Which of the following best explains why Rust's Rc<T> type is neither Send nor Sync?
Show the answer
Answer: d · Its internal reference count is not atomically updated, making concurrent access unsafe.
The card explicitly states that "Rc<T> (non-atomic reference counting) is neither Send nor Sync," indicating that its non-atomic reference count is the core reason for its thread-unsafety. While Rc<T> is indeed for single-threaded use (option A), this is a consequence of its non-atomic design, not the fundamental reason it fails Send/Sync checks.
Read the full bite: Send vs. Sync: Rust's Thread Safety Contracts
Question 18 of 30
Why does CSP-style message passing make concurrent systems easier to reason about than shared-memory threading?
Show the answer
Answer: b · Because each process is understood sequentially and all interaction is visible at channel boundaries
The card explains that isolation lets you understand each worker's logic sequentially, with all coupling explicit through channel data at the boundaries. Option A is tempting but wrong because channels are themselves the synchronization mechanism in CSP, not a way to remove coordination.
Read the full bite: CSP: Model Concurrency with Message Passing
Question 19 of 30
What is the fundamental role of synchronization primitives (like channels or mutexes) in Go's memory model?
Show the answer
Answer: d · To establish a "happens-before" relationship, guaranteeing memory writes are visible across goroutines.
Synchronization actions like channel sends/receives or mutex locks/unlocks create a "happens-before" relationship, which guarantees that memory operations before the action in one goroutine are visible to operations after the corresponding action in another. While the memory model addresses issues caused by reordering, synchronization primitives don't prevent reordering; rather, they provide guarantees about visibility despite reordering.
Question 20 of 30
What fundamental guarantee provided by std::thread::scope enables spawned threads to safely borrow local variables from their parent?
Show the answer
Answer: c · It ensures that all threads created within its block are joined before the block's execution completes.
The card explains that the 'scope block acts as the supervisor, guaranteeing that all threads started within it will finish before the block exits.' This join guarantee is what allows the Rust compiler to safely permit borrowing of local variables. Option B describes the requirement for standard std::thread::spawn, which scoped threads aim to circumvent.
Read the full bite: Rust's Scoped Threads: Borrowing Across Threads Safely
Question 21 of 30
When developing a build.rs script, what is a crucial distinction regarding cfg! macros, especially in cross-compilation scenarios?
Show the answer
Answer: a · cfg! macros in build.rs evaluate conditions based on the host system where the build script runs, which can cause problems when cross-compiling.
The card explicitly states that "cfg! macros check the build host's architecture, not the target's," making option A correct. This is a critical "footgun" because it means `cfg!` will not provide the correct target platform information for cross-compilation, unlike what option D suggests.
Read the full bite: Rust Build Scripts: Compiling More Than Just Rust
Question 22 of 30
For which scenario would using Rust Cargo features be an inappropriate choice?
Show the answer
Answer: a · Allowing a user to select between two mutually exclusive data processing algorithms at runtime.
Cargo features are for compile-time configuration, not runtime choices. If a user needs to decide between options while the program is running, standard language constructs like enums or trait objects should be used instead. The other options describe valid use cases for Cargo features, as they involve compile-time conditional inclusion of code or dependencies.
Read the full bite: Rust Cargo Features: Conditional Compilation & Dependencies
Question 23 of 30
A Rust developer is evaluating the runtime performance of a new sorting algorithm. Which command should they use for accurate results?
Show the answer
Answer: d · cargo run --release
To accurately measure performance, the code must be compiled with optimizations enabled, which the 'release' profile provides. 'cargo run --release' uses this profile, while 'cargo run' defaults to the unoptimized 'dev' profile, leading to misleadingly slow results.
Read the full bite: Rust Build Profiles: Tune for Speed vs. Debugging
Question 24 of 30
Why can a single json.Decoder consume a gzip-compressed file and an HTTP response body without code changes?
Show the answer
Answer: a · Both implement io.Reader, so the decoder depends only on that interface, not the concrete source
The decoder is written against the io.Reader interface, so any source satisfying it composes interchangeably. It streams chunks rather than buffering everything, and there is no runtime type branching or shared base class involved.
Question 25 of 30
What is the primary mechanism by which Go's context package prevents resource leaks in long-running operations when a deadline is exceeded?
Show the answer
Answer: b · It propagates a cancellation signal to derived operations, allowing them to gracefully stop.
The card states that context acts as a "control wire" that propagates cancellation signals to derived contexts and their associated work, allowing them to stop gracefully and prevent resource leaks. Option A is incorrect because context signals for graceful termination; it does not forcefully terminate goroutines, which must explicitly listen for the cancellation signal.
Read the full bite: Go's `context` Package: Propagating Cancellation and Deadlines
Question 26 of 30
In which scenario would using a Foreign Function Interface (FFI) likely introduce an undesirable performance overhead?
Show the answer
Answer: b · Calling a simple, frequently used mathematical helper function written in C from a Python application.
The card states that FFI should be avoided if the boundary between languages is 'chatty' (many frequent, small calls) because the overhead of marshalling data can become a bottleneck. Calling a simple, frequently used function fits this description, as the marshalling cost per call might outweigh the benefit. The other options represent ideal use cases for FFI, involving complex, essential, or performance-critical foreign code.
Read the full bite: Foreign Function Interface (FFI): Calling Other Languages
Question 27 of 30
Why is it generally advised to avoid using Go fuzz testing on functions that perform network calls or database queries?
Show the answer
Answer: d · Such functions introduce non-determinism and significant performance overhead, which are detrimental to the fuzzer's efficiency and reproducibility.
The card explicitly states to avoid fuzzing functions that are slow or non-deterministic, like those with external side effects, because "Speed and determinism are critical for the fuzzer to work efficiently and for failures to be reproducible." While external calls can indeed lead to integration issues or data corruption, the primary reason for avoidance in fuzz testing, as per the card, is the impact on the fuzzer's performance and ability to reliably reproduce failures.
Read the full bite: Go Fuzz Testing: Automated Bug Discovery
Question 28 of 30
What is a primary challenge when using cargo-fuzz to effectively test a function that expects highly structured input, like a complex file format parser?
Show the answer
Answer: a · The fuzzer often struggles to generate inputs that are syntactically valid enough to explore deeper logic paths.
The card highlights that 'the main footgun is assuming random bytes are enough; effective fuzzing needs structure-aware inputs.' For highly structured data, purely random bytes are unlikely to pass initial parsing, preventing the fuzzer from exploring deeper logic. Option B describes a limitation of fuzzing's error detection, not the challenge of generating effective inputs for structured data.
Question 29 of 30
For which scenario is the Go Execution Tracer the most appropriate diagnostic tool?
Show the answer
Answer: c · Understanding why goroutines are frequently blocked or experiencing high lock contention.
The Go Execution Tracer is specifically designed to diagnose complex concurrency issues like high lock contention and blocked goroutines by visualizing runtime events. It is not intended for continuous production monitoring due to its overhead, nor is it the primary tool for CPU-bound issues or memory leak detection.
Read the full bite: Go Execution Tracer: Pinpointing Concurrency Bottlenecks
Question 30 of 30
What is a significant challenge when developing Rust procedural macros?
Show the answer
Answer: a · The code they generate is unhygienic, potentially causing name collisions with local variables in the user's scope.
The card explicitly states that the "primary reason to be cautious is their unhygienic nature" and that generated code can clash with local variables, leading to name collisions. Option B is incorrect because the card advises using declarative macros for simple substitutions, not procedural macros.
Read the full bite: Rust Procedural Macros: Code That Writes Code
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.