Skip to content
tezvyn:

Top 30 Easy Go & Rust Interview Questions and Answers for Freshers

30 easy multiple-choice Go & Rust interview questions, the ones an interviewer opens with: definitions, everyday syntax, and the quick checks that you have really used it. They come from 30 bites in the Go & Rust library, the gentlest slice of the 132 Go & Rust interview 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.

  1. Question 1 of 30

    When evaluating a new cloud infrastructure project, which statement accurately reflects the trade-off between using Rust versus Go?

    Show the answer

    Answer: a · Rust provides deterministic latency and compile-time data-race safety at the cost of a steeper learning curve, whereas Go trades runtime GC overhead for simplicity and faster onboarding.

    B is correct because it accurately pairs Rust's deterministic, zero-cost memory safety and compile-time data-race prevention with its steeper learning curve, while recognizing Go's GC introduces runtime overhead in exchange for simplicity and faster onboarding. C is a tempting distractor because Go does automate memory reclamation, but its GC does not prevent data races—memory safety and concurrency safety are distinct, and Go leaves more thread-safety responsibility to the developer.

    Read the full bite: Compare Go's GC and Rust's ownership across performance, productivity, and safety

  2. Question 2 of 30

    You add a new variant to an error type during a large refactor. Why does Rust typically surface every place needing an update more reliably than Go?

    Show the answer

    Answer: d · Rust's exhaustive match makes non-updated handling sites fail to compile

    Adding an enum variant makes existing exhaustive matches incomplete, so Rust's compiler flags each site. Go's error values do not force callers to branch, so it does not flag missed sites; Rust does not auto-rewrite code.

    Read the full bite: Refactoring under Go simplicity versus Rust correctness

  3. Question 3 of 30

    If you write let x = 5 in Rust and x := 5 in Go, which statement about mutability is correct?

    Show the answer

    Answer: c · The Rust declaration is immutable, while the Go declaration allows reassignment without extra keywords

    Rust makes bindings immutable by default, so let x = 5 cannot be reassigned without let mut, while Go variables declared with := or var are mutable by default. Option D is a common misconception because both var and := create mutable bindings in Go, and true immutability requires const.

    Read the full bite: How does Go's variable declaration and mutability differ from Rust?

  4. Question 4 of 30

    What is the main mechanical difference between Go's for i := 1; i <= 5; i++ and Rust's for i in 1..=5?

    Show the answer

    Answer: a · Go uses a C-style control statement that manually manages the index, while Rust consumes an iterator hiding index management.

    Go's for is a control statement with explicit initialization, condition, and increment, whereas Rust's for consumes an iterator produced by the inclusive range. Option D is a tempting distractor because both loops look similar, but claiming they are semantically identical misses the statement-driven versus iterator-based gap.

    Read the full bite: Write a 1-to-5 loop in Go and Rust

  5. Question 5 of 30

    Which statement best explains why you must reassign the result of append to the original slice variable in Go?

    Show the answer

    Answer: d · The append function may allocate a new backing array when capacity is exceeded, so the returned slice header must replace the original variable.

    append may allocate an entirely new backing array when capacity is exhausted, so the returned slice header must replace the original variable or data will be lost. The most tempting distractor claims append always modifies in place, which is false and leads to silent bugs when a reallocation occurs.

    Read the full bite: How do you append to a Go slice and why reassign?

  6. Question 6 of 30

    Given enum WebEvent { PageLoad, PageUnload, KeyPress(char) }, which line correctly instantiates the KeyPress variant with 'q'?

    Show the answer

    Answer: d · let press = WebEvent::KeyPress('q');

    Rust namespaces enum variants under the type with double colons, so WebEvent::KeyPress('q') is correct. WebEvent.KeyPress('q') is invalid because Rust does not use dot notation for enum variants, unlike some other languages.

    Read the full bite: Define a WebEvent enum with PageLoad, PageUnload, and KeyPress

  7. Question 7 of 30

    If you retrieve a User pointer from a map[int]*User and modify its Name field, what happens?

    Show the answer

    Answer: a · The change is visible through every reference to that same User struct

    Because the map stores pointer addresses, retrieving an entry yields a copy of the pointer that still refers to the same underlying struct; modifying a field therefore affects all references. Option B is tempting because maps do copy values on retrieval, but copying a pointer does not isolate the struct it points to.

    Read the full bite: Define a User struct and map of IDs to pointers

  8. Question 8 of 30

    How do Go and Rust respectively determine whether a function or type is accessible outside its immediate scope?

    Show the answer

    Answer: c · Go exports identifiers that start with an uppercase letter across packages, while Rust uses the pub keyword to make items visible outside their module.

    Go exports uppercase identifiers across packages, while Rust requires explicit pub for module-level visibility. Distractor B is tempting because it correctly names capitalization and pub but wrongly limits Go to file-level scope and Rust to unrestricted crate-wide visibility.

    Read the full bite: How do Go and Rust control visibility of functions and types?

  9. Question 9 of 30

    In module example.com/shop, directory helpers/ contains files with package utils. What is the correct way to import and use ProcessOrder?

    Show the answer

    Answer: b · Import example.com/shop/helpers and call utils.ProcessOrder

    The import path is always the module path plus the subdirectory (helpers), while the package clause (utils) sets the qualifier used in code. Option A is wrong because it assumes the directory name becomes the code qualifier, a common beginner misconception.

    Read the full bite: Go package declaration, directory name, and import path relationship

  10. Question 10 of 30

    Why does a local variable in Go sometimes get allocated on the heap instead of the stack?

    Show the answer

    Answer: d · The compiler cannot prove the variable's lifetime ends before the function returns

    Go's compiler stack-allocates local variables when it can prove their lifetime is bounded by the function scope, so a value only escapes to the heap when that proof fails. The first option is wrong because the GC does not manage stack memory; stack-allocated locals are reclaimed instantly by moving the stack pointer when the function returns, with no GC involvement.

    Read the full bite: Describe Go's memory management, garbage collection, and trade-offs

  11. Question 11 of 30

    What mechanism allows Rust to manage memory safely without a garbage collector or manual free calls?

    Show the answer

    Answer: d · The borrow checker enforces ownership rules at compile time, automatically dropping values when their owner goes out of scope.

    Rust's borrow checker validates the three ownership rules statically, ensuring memory is freed automatically when an owner goes out of scope without runtime overhead. Reference counting is a runtime technique used by some other languages, and Rust explicitly does not rely on manual freeing.

    Read the full bite: Explain Rust's Ownership and its three compiler-enforced rules

  12. Question 12 of 30

    Why does Rust enforce either one mutable reference or many immutable references, but never both?

    Show the answer

    Answer: d · To guarantee memory safety and prevent data races without relying on a garbage collector

    Rust's borrowing rules are a compile-time strategy to guarantee memory safety and data-race freedom without a garbage collector. The most tempting distractor claims Rust bans multiple pointers entirely, but the card explicitly states you can have many immutable references; the rule only forbids simultaneous mutable and immutable access.

    Read the full bite: Why are Rust's borrowing rules stricter than Go's pointers?

  13. Question 13 of 30

    A Go function returns (User, error). What must the caller do before using the User value?

    Show the answer

    Answer: c · Check whether the error is non-nil and handle it before using User

    Go conventions require checking if the error is non-nil before using the result, since a non-nil error signals that the other return value is a zero value and unsafe to use. Option B is tempting but wrong because the zero-value result may not be nil, and the error is the authoritative success signal.

    Read the full bite: How do you idiomatically return a recoverable error and result in Go?

  14. Question 14 of 30

    What happens when a Result returned by a function is completely ignored in Rust?

    Show the answer

    Answer: c · The compiler issues a warning because Result is annotated with must_use

    Result carries the must_use attribute, so ignoring it triggers an unused_must_use compiler warning by default, not a hard error. Option B is tempting but wrong because compilation still succeeds unless the warning is explicitly elevated to deny.

    Read the full bite: What are Rust Result's variants and how does the compiler enforce handling?

  15. Question 15 of 30

    When some_call()? evaluates to Err inside a function returning Result, what happens?

    Show the answer

    Answer: a · It immediately returns the Err from the current function

    The ? operator immediately returns the Err from the current function, enabling propagation via the Try and FromResidual traits, whereas unwrap panics on Err rather than returning to the caller.

    Read the full bite: Rust's operator equivalent to Go's if err != nil return err

  16. Question 16 of 30

    You define a struct MyReader with method Read(b []byte) (int, error). What is required before assigning a MyReader value to an io.Reader variable?

    Show the answer

    Answer: d · Nothing; the assignment compiles because the method signatures match exactly.

    Go uses implicit structural typing, so MyReader automatically satisfies io.Reader by implementing the exact Read signature without any declaration. Distractor A is wrong because Go has no implements keyword or explicit conformance clause.

    Read the full bite: How does a Go type satisfy an interface? Provide an io.Reader example.

  17. Question 17 of 30

    Which syntax correctly implements a trait for a specific concrete type in Rust?

    Show the answer

    Answer: c · impl TraitName for Type provides concrete method bodies for a specific struct or enum

    The impl TraitName for Type syntax is required to attach concrete logic to a specific struct or enum. Option A is wrong because impl Type alone defines inherent methods, not a trait implementation, and omitting for is a common beginner mistake.

    Read the full bite: What is the difference between defining a Rust trait and implementing it?

  18. Question 18 of 30

    What is the main reason Go programs can spawn hundreds of thousands of goroutines but only thousands of OS threads?

    Show the answer

    Answer: d · Goroutines are managed by the Go runtime with small growable stacks, while OS threads are kernel-managed with large fixed stacks.

    The Go runtime multiplexes many goroutines onto a smaller pool of OS threads and allocates them small initial stacks that grow on demand, keeping per-unit memory low enough for massive concurrency. A tempting distractor claims goroutines bypass OS threads entirely, but the runtime still uses OS threads as the underlying execution vehicles.

    Read the full bite: What is the fundamental difference between a goroutine and an OS thread?

  19. Question 19 of 30

    In Rust, a type with unsynchronized interior mutability like Cell is correctly classified how?

    Show the answer

    Answer: d · It is Send but not Sync because moving it is safe yet sharing references risks data races

    Cell is Send because transferring ownership to another thread is safe, but it is not Sync because sharing references across threads would allow unsynchronized mutation and data races. The 'neither' distractor is a common misconception that conflates Cell with Rc, which actually lacks both traits.

    Read the full bite: How do Send and Sync prevent data races? Give a Send-but-not-Sync example.

  20. Question 20 of 30

    Why does a single goroutine deadlock when it sends on an unbuffered channel with no receiver?

    Show the answer

    Answer: a · The send waits forever for a receive that never happens

    An unbuffered channel has zero capacity, so every send blocks until a matching receive accepts the value; with no receiver, the send blocks forever. Distractor C is wrong because unbuffered channels have no buffer at all, so fullness is not the issue.

    Read the full bite: Buffered vs unbuffered Go channels and deadlock scenario

  21. Question 21 of 30

    A junior teammate asks why both go.mod and go.sum must be committed. What is the correct explanation?

    Show the answer

    Answer: c · go.mod declares minimum required versions, while go.sum stores cryptographic checksums to verify downloaded content.

    go.mod is a manifest that declares the module path and minimum required versions, while go.sum is an integrity log containing cryptographic checksums that verify downloaded module content and prevent supply-chain tampering. The distractor claiming go.mod pins exact versions confuses it with a lockfile, but Go uses minimal version selection and go.sum ensures integrity rather than locking versions.

    Read the full bite: How do you initialize and manage Go dependencies?

  22. Question 22 of 30

    When should you commit Cargo.lock to version control, and why?

    Show the answer

    Answer: c · Only for applications, because it ensures reproducible builds with exact dependency versions

    Cargo.lock should be committed for applications because it pins exact resolved versions, guaranteeing reproducible builds. The most tempting distractor claims libraries should commit it, but that hides integration conflicts by preventing downstream applications from resolving their own compatible dependency graph.

    Read the full bite: What is the difference between Cargo.toml and Cargo.lock?

  23. Question 23 of 30

    Which pair correctly matches the modern idiomatic convenience function to its return type?

    Show the answer

    Answer: a · Go os.ReadFile returns ([]byte, error); Rust std::fs::read returns Result<Vec<u8>>

    Go 1.16 introduced os.ReadFile returning ([]byte, error), while Rust's std::fs::read returns Result<Vec<u8>>. Option D is tempting because ioutil.ReadFile did return that type, but it has been deprecated since Go 1.16.

    Read the full bite: Read a file into a byte slice in Go and Rust

  24. Question 24 of 30

    When implementing a synchronous TCP server using only standard libraries, how do Go and Rust differ in handling multiple concurrent connections?

    Show the answer

    Answer: c · Go spawns a goroutine for each accepted net.Conn, while Rust typically moves each std::net::TcpStream into a dedicated thread

    The card states that Go pairs listener.Accept with goroutines for concurrent handling, while Rust moves each TcpStream into a dedicated thread when using only the standard library. Option B is tempting because Rust's std::net is indeed blocking, but it wrongly places Go at the HTTP layer and incorrectly suggests Rust cannot spawn threads for concurrency.

    Read the full bite: Build a TCP server in Go and Rust using standard libraries

  25. Question 25 of 30

    Which statement accurately contrasts JSON serialization approaches in Go and Rust?

    Show the answer

    Answer: c · Go's standard library includes a reflection-based JSON encoder, while Rust relies on external crates like serde to derive serialization traits at compile time.

    Go ships encoding/json in its standard library and uses runtime reflection, whereas Rust intentionally omits serialization from std and delegates to external crates like serde for compile-time derived traits. Distractor B is tempting because derive macros can look like reflection, but they generate code at compile time rather than inspecting types at runtime.

    Read the full bite: Serialize a Go struct to JSON and contrast with Rust

  26. Question 26 of 30

    When organizing multiple test cases for the same Go function, which approach is considered unidiomatic and should be avoided?

    Show the answer

    Answer: b · Extracting each scenario into its own top-level Test function

    Creating a separate top-level Test function for every scenario leads to copy-paste duplication and painful updates, which is the exact anti-pattern table-driven tests are meant to eliminate. Option D is actually standard practice, so selecting it confuses the table definition with the organizational anti-pattern.

    Read the full bite: How do you write a table-driven test in Go?

  27. Question 27 of 30

    Why can unit tests call private functions while integration tests cannot?

    Show the answer

    Answer: d · Unit tests are child modules in the same crate and can access private ancestor items, but integration tests are external crates

    Unit tests are child modules within the same crate, so they can access private items in ancestor modules via super::, whereas integration tests are compiled as separate external crates and are restricted to the public API. #[cfg(test)] only controls conditional compilation, not visibility, so distractor A conflates the annotation with privacy rules.

    Read the full bite: How does Rust differentiate unit and integration tests?

  28. Question 28 of 30

    When should you prioritize running go test -race?

    Show the answer

    Answer: a · Testing a concurrent app with shared mutable state under realistic workloads

    The race detector dynamically finds unsynchronized concurrent memory accesses, so it is crucial for shared mutable state under realistic test workloads. It does not catch deadlocks, nor is it a static analyzer, and its roughly ten times overhead makes always-on production use impractical.

    Read the full bite: What is go test -race and when is it crucial?

  29. Question 29 of 30

    Which statement accurately describes how go generate differs from a build system like make?

    Show the answer

    Answer: d · go generate is invoked manually and intentionally lacks dependency analysis

    go generate is executed explicitly by developers and was deliberately designed to avoid dependency analysis, which is central to make. The tempting idea that it runs during go build is wrong because the Go toolchain never invokes it automatically.

    Read the full bite: What is go generate and how does it differ from make?

  30. Question 30 of 30

    Which statement correctly distinguishes how Rust's declarative and procedural macros operate?

    Show the answer

    Answer: a · Declarative macros use macro_rules! for pattern-based expansion, while procedural macros manipulate tokens to generate code at compile time

    Declarative macros rely on macro_rules! for pattern matching and syntax expansion, whereas procedural macros consume and transform token streams to generate code at compile time. Option C reverses these roles, which is a frequent point of confusion.

    Read the full bite: What are Rust's two macro categories and use cases?

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.

Get it on Google PlayiPhone app coming soon