Top 30 Go & Rust Concepts Quiz
30 multiple-choice questions on the Go & Rust fundamentals, drawn from 30 bites in the Go & Rust 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 fundamental principle guiding Go's design?
Show the answer
Answer: d · Optimizing for practical engineering challenges in large systems.
Go was created to solve practical problems like slow builds and complexity in massive codebases, prioritizing engineering concerns such as maintainability and team productivity. It explicitly avoids being a research language or focusing on novel paradigms.
Read the full bite: Go's Design Philosophy: Engineering Over Novelty
Question 2 of 30
What is a key advantage of Rust's philosophy of bundling its official documentation with the language installation?
Show the answer
Answer: c · It guarantees developers have immediate, offline access to comprehensive learning materials.
The card states that bundling the documentation ensures every user has immediate, offline access to a high-quality learning resource. Option D is incorrect because documentation adds to the download size, it doesn't reduce it.
Read the full bite: Rust's Philosophy: Documentation and Community First
Question 3 of 30
A Go server spawns a goroutine per incoming request, and one handler blocks forever reading from a channel that nothing will ever write to. What happens to that goroutine?
Show the answer
Answer: b · It stays alive indefinitely, quietly consuming its stack memory, because Go never force-cancels a blocked goroutine on its own
Go has no automatic timeout or forced cancellation for a blocked goroutine, so it simply stays parked, leaking its stack, until the process exits or something explicitly unblocks it. The runtime does not kill it after a timeout, a single blocked goroutine does not crash the whole program since Go only reports a deadlock when every goroutine is blocked at once, and the garbage collector does not collect a goroutine that could still be unblocked.
Question 4 of 30
How does a concrete type in Go become an implementer of an interface?
Show the answer
Answer: b · By defining all the methods specified in the interface's method set.
A type satisfies an interface implicitly by implementing its methods, without an 'implements' keyword. Option B accurately describes this structural typing, where a type automatically satisfies an interface if it provides all the required methods. Option C is incorrect because Go does not use an explicit 'implements' keyword.
Read the full bite: Go Interfaces: Describe Behavior, Not Data
Question 5 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 6 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 7 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 8 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 9 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 10 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 11 of 30
Regarding variable mutability, what is the fundamental difference between Rust and Go?
Show the answer
Answer: d · Rust variables are immutable by default and need an explicit keyword for mutability, whereas Go variables are mutable by default.
The card explicitly states that Rust variables are immutable by default and require the 'mut' keyword to become mutable, while Go variables are mutable by default. Option A incorrectly swaps the default behaviors of the two languages.
Read the full bite: Go vs. Rust: Variable Mutability by Default
Question 12 of 30
Given two slices, s1 and s2, where s2 is created by slicing s1, what happens if you modify an element in s2?
Show the answer
Answer: d · The modification will also be visible in s1, because both slices reference the same underlying array.
Slices are descriptors that point to a segment of an underlying array. When s2 is created by slicing s1, both slices typically point to the same underlying array. Therefore, modifying an element through s2 will also reflect the change when accessing the same element through s1. The most tempting distractor (C) is incorrect because slices do not copy their data when created from another slice; they share the underlying storage.
Question 13 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 14 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 15 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 16 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 17 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 18 of 30
What is the immediate consequence of attempting to assign a value to a Go map that has been declared but not initialized?
Show the answer
Answer: c · The program will encounter a runtime panic.
The card explicitly states that 'Writing to a nil map causes a runtime panic.' A declared-only map is nil, meaning it points to no underlying hash table structure. While some errors are caught at compile time, this specific issue is a runtime problem because the type system allows the declaration, but the operation itself is invalid without an initialized structure.
Question 19 of 30
What happens when a Rust Vec<T> is full and a new item is pushed into it?
Show the answer
Answer: a · It allocates a larger memory block, copies all existing items, then adds the new item.
When a Vec<T> is full, it reallocates by finding a new, larger contiguous memory block, copying all existing elements to it, and then adding the new element. This ensures the vector remains growable. Option D is incorrect because Vec<T> is designed to grow automatically, not to error out when capacity is reached.
Question 20 of 30
Which action is most likely to lead to incorrect behavior or data loss when using a Rust HashMap?
Show the answer
Answer: b · Modifying a key's internal state in a way that changes its hash value after it has been inserted.
Modifying a key's hash-relevant properties after insertion violates the HashMap's core invariants, leading to undefined behavior like panics or incorrect lookups. While using non-cryptographically secure keys can lead to performance degradation under attack (HashDoS), it doesn't inherently cause the map's internal logic to break or data to be lost in the same way as modifying an inserted key.
Read the full bite: Rust HashMap: Fast, Secure Key-Value Storage
Question 21 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 22 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 23 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 24 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 25 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 26 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 27 of 30
To create reusable functionality that can be easily shared across different Rust projects, where should the core logic primarily reside?
Show the answer
Answer: a · Inside a library crate, typically rooted at src/lib.rs.
The card explicitly states, "When you want to create shared, reusable functionality for other projects, you build a library crate." Option C is incorrect because `main.rs` is for the executable's entry point, not for shared logic, which the card advises against.
Question 28 of 30
To make a struct defined within a submodule vegetables (located at src/garden/vegetables.rs) accessible from the crate root (src/main.rs), which visibility declaration is absolutely necessary?
Show the answer
Answer: d · The vegetables module, the garden module, and the struct must all be explicitly marked pub.
The card states that 'Every pub keyword here is essential; without them, the modules and the struct would be private and inaccessible from main.rs.' This means all modules and the item itself in the path must be public. The 'use' keyword only creates a shortcut to an item's path; it does not grant public visibility.
Question 29 of 30
What is the primary mechanism Go uses to identify a program as an executable rather than a reusable library?
Show the answer
Answer: a · Declaring `package main` and defining a `func main()` function.
The card explicitly states that `package main` and its `main()` function serve as the unambiguous signal for the Go compiler to create a runnable executable. Option D is incorrect because `go.mod` manages modules and dependencies, not the program's execution type.
Read the full bite: Go's Entry Point: The `main` Package and Function
Question 30 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
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.