Go Programming Skills Assessment — Questions and Answers
Question 1: Which of the following if conditions are valid in Go?
- if x := 10; x > 5 {} (Correct answer)
- if (x > 5) (Correct answer)
- if x := "test" {}
- if x > 5 then {}
Correct answer: if x := 10; x > 5 {}
Go's `if` statements support a short statement before the condition, like `if x := 10; x > 5 {}`, which declares and initializes `x` within the scope of the `if` statement. Additionally, `if (x > 5)` is valid, as parentheses around the condition are allowed, though `if x > 5` is more idiomatic. Option C uses `then`, which is not Go syntax, and option D is missing a boolean condition after the short variable declaration.
Question 2: What is the purpose of `sync.Once`?
- Prevent goroutine reuse
- Execute a function exactly one time across all goroutines (Correct answer)
- Run a goroutine exactly once
- Lock a mutex once and never unlock
Correct answer: Execute a function exactly one time across all goroutines
`sync.Once` guarantees that a function is executed exactly once, regardless of how many goroutines call `Do`, making it ideal for initialization.
Question 3: Which of the following best describes polymorphism in Go?
- Using interface variables to call methods on different concrete types (Correct answer)
- Inheritance from base structs
- Using generics only
- Method overloading by parameter count
Correct answer: Using interface variables to call methods on different concrete types
Go achieves polymorphism through interfaces: a variable of interface type can hold any concrete type that satisfies it, and method calls dispatch to the concrete type.
Question 4: How do you run only a specific test function named `TestAdd`?
- go test -func TestAdd
- go test TestAdd
- go test -only TestAdd
- go test -run TestAdd (Correct answer)
Correct answer: go test -run TestAdd
`go test -run TestAdd` runs only test functions matching the regular expression `TestAdd`, enabling targeted test execution.
Question 5: What is the primary purpose of the `sync.WaitGroup` in Go?
- Cancel goroutine execution
- Limit goroutine count
- Wait for a collection of goroutines to finish (Correct answer)
- Share data between goroutines
Correct answer: Wait for a collection of goroutines to finish
`sync.WaitGroup` blocks the calling goroutine until all goroutines tracked via `Add`, `Done`, and `Wait` have completed.
Question 6: What does `go mod tidy` do?
- Deletes the module cache
- Formats go.mod file
- Updates all dependencies to latest
- Removes unused dependencies and adds missing ones in go.mod (Correct answer)
Correct answer: Removes unused dependencies and adds missing ones in go.mod
`go mod tidy` adds any missing module requirements and removes unused ones, keeping `go.mod` and `go.sum` consistent with the source code.
Question 7: What does the Go scheduler use as its concurrency model?
- Actor model
- Single-threaded event loop
- M:N threading (many goroutines on fewer OS threads) (Correct answer)
- One OS thread per goroutine
Correct answer: M:N threading (many goroutines on fewer OS threads)
Go uses an M:N scheduler that multiplexes many goroutines (M) onto a smaller number of OS threads (N), managed by the Go runtime.
Question 8: What does garbage collection do in Go?
- Manually frees allocated memory.
- Prevents memory leaks by stopping cyclic references. (Correct answer)
- Automatically reclaims memory that is no longer in use. (Correct answer)
- Requires explicit invocation by the programmer.
Correct answer: Prevents memory leaks by stopping cyclic references.
Go features an automatic garbage collector that manages memory allocation and deallocation. Its primary role is to automatically identify and reclaim memory that is no longer referenced by the program, preventing memory leaks and reducing the burden on developers for manual memory management. This process ensures efficient use of system resources and effectively handles cyclic references, which can otherwise lead to memory leaks.
Question 9: How do you specify a major version upgrade (v2+) in a Go module import path?
- Append `/v2` (or higher) to the module path (Correct answer)
- go get -major
- Set GOVERSION=2 environment variable
- Use replace directive in go.mod
Correct answer: Append `/v2` (or higher) to the module path
Go module semantic versioning requires appending `/v2`, `/v3`, etc. to the module path for major versions ≥2, e.g., `github.com/pkg/errors/v2`.
Question 10: What file suffix is required for Go test files?
- _spec.go
- _test.go (Correct answer)
- .gotest
- _unit.go
Correct answer: _test.go
Go test files must end with `_test.go`; the `go test` tool recognizes and compiles these files only during testing, not in regular builds.
Question 11: Can a Go interface be embedded in another interface?
- Yes, but only one level deep
- No, Go does not support interface composition
- No, only structs can be embedded
- Yes, to compose larger interfaces from smaller ones (Correct answer)
Correct answer: Yes, to compose larger interfaces from smaller ones
Go supports interface embedding, allowing you to compose interfaces; for example, `io.ReadWriter` embeds `io.Reader` and `io.Writer`.
Question 12: What naming convention determines if a Go identifier is exported from a package?
- Add `//export` comment above it
- Prefix with `export`
- Prefix with `pub`
- Start the name with an uppercase letter (Correct answer)
Correct answer: Start the name with an uppercase letter
In Go, identifiers starting with an uppercase letter are exported (public), while lowercase identifiers are unexported (package-private).
Question 13: What is the Go module proxy and why is it used?
- A reverse proxy for Go HTTP servers
- A tool for proxying network requests in tests
- A local cache of compiled binaries
- A server that caches module downloads for faster and more reliable fetching (Correct answer)
Correct answer: A server that caches module downloads for faster and more reliable fetching
The Go module proxy (default: `proxy.golang.org`) caches module source code, improving download speed, reliability, and availability of older versions.
Question 14: In the following code, what does the embedded type enable? ```go type Animal struct{ Name string } func (a Animal) Speak() string { return a.Name } type Dog struct{ Animal; Breed string } d := Dog{Animal: Animal{"Rex"}, Breed: "Lab"} fmt.Println(d.Speak()) ```
- Only `d.Animal.Speak()` works; promotion does not apply here
- Dog inherits Animal's data but not its methods
- Calling `d.Speak()` directly without qualifying it as `d.Animal.Speak()` (Correct answer)
- A compilation error because Dog embeds a non-interface type
Correct answer: Calling `d.Speak()` directly without qualifying it as `d.Animal.Speak()`
Struct embedding promotes the embedded type's methods to the outer struct, so `d.Speak()` works as a shorthand for `d.Animal.Speak()`.
Question 15: What does the `select` statement do when multiple channels are ready simultaneously?
- Executes the first case in order
- Executes all ready cases
- Picks a ready case pseudo-randomly (Correct answer)
- Panics with ambiguous select
Correct answer: Picks a ready case pseudo-randomly
When multiple cases in a `select` are ready, Go picks one uniformly at random to prevent starvation and avoid deterministic bias.
Question 16: What does `len(ch)` return for a buffered channel?
- Number of elements currently buffered (Correct answer)
- Channel capacity
- Number of goroutines waiting to send
- Always 0
Correct answer: Number of elements currently buffered
`len(ch)` returns the number of elements currently queued (unread) in the channel's buffer.
Question 17: When should panic be used instead of returning an error in Go?
- For minor errors that can be ignored.
- When an unexpected and unrecoverable condition occurs. (Correct answer)
- To debug your code.
- To simplify error handling in a function.
Correct answer: When an unexpected and unrecoverable condition occurs.
`panic` in Go should be reserved for truly exceptional and unrecoverable situations, such as programming errors or critical system failures that prevent the program from continuing safely. For most anticipated errors, returning an `error` value is the idiomatic and preferred approach, allowing the caller to handle or recover gracefully. Using `panic` for minor errors would lead to program crashes.
Question 18: Which function returns the number of logical CPUs available to the current process?
- runtime.NumCPU() (Correct answer)
- sync.NumCPU()
- runtime.GOMAXPROCS(0)
- os.NumCPU()
Correct answer: runtime.NumCPU()
`runtime.NumCPU()` returns the number of logical CPUs on the machine, while `GOMAXPROCS` sets/gets the limit used by the scheduler.
Question 19: What does `select { case <-ch: default: }` do?
- Blocks until ch receives
- Drains all values from ch
- Closes ch if empty
- Performs a non-blocking receive from ch (Correct answer)
Correct answer: Performs a non-blocking receive from ch
A `select` with a `default` case performs a non-blocking operation; if no case is ready, `default` executes immediately.
Question 20: How can you implement a timeout for a channel receive in Go?
- Use context.Deadline only
- Use time.Sleep before receiving
- Use select with a time.After case (Correct answer)
- Use ch.Timeout(d)
Correct answer: Use select with a time.After case
`select { case v := <-ch: ... case <-time.After(d): ... }` implements a receive timeout by racing the channel against a timer channel.
Question 21: Which context function creates a context that can be cancelled manually?
- context.WithTimeout()
- context.Background()
- context.WithCancel() (Correct answer)
- context.TODO()
Correct answer: context.WithCancel()
`context.WithCancel` returns a derived context and a `cancel` function; calling `cancel()` propagates cancellation to all goroutines watching that context.
Question 22: Which of the following functions are used for memory allocation in Go?
- allocate
- new (Correct answer)
- make (Correct answer)
- malloc
Correct answer: new
In Go, `new` is used to allocate memory for a value of a specified type and returns a pointer to the zero-initialized value. `make` is used specifically for slices, maps, and channels, allocating and initializing their internal data structures. `allocate` and `malloc` are not Go built-in functions for memory allocation.
Question 23: When should you prefer a pointer receiver over a value receiver for a Go method?
- Pointer receivers should always be avoided for simplicity
- Whenever the method returns a value
- When the method needs to mutate the struct or when the struct is large to avoid copying (Correct answer)
- Only when the struct contains a map or slice
Correct answer: When the method needs to mutate the struct or when the struct is large to avoid copying
Pointer receivers are preferred when the method modifies the struct or when copying the struct would be expensive due to its size.
Question 24: What is the empty interface `interface{}` (or `any`) equivalent to?
- An interface with one method
- A nil pointer
- A type that holds any value since all types satisfy it (Correct answer)
- A map of type metadata
Correct answer: A type that holds any value since all types satisfy it
The empty interface has no methods, so every type satisfies it, allowing `interface{}` (or `any` in Go 1.18+) to hold a value of any type.
Question 25: What is the `internal` package convention in Go?
- Packages named `internal` are compiled differently
- Code in an `internal` directory can only be imported by code in its parent tree (Correct answer)
- Internal packages skip type checking
- Internal packages are hidden from the module system
Correct answer: Code in an `internal` directory can only be imported by code in its parent tree
The `internal` directory restriction prevents external packages from importing its contents; only packages rooted at the parent of `internal` may import it.
Question 26: Which atomic operation in `sync/atomic` swaps a value only if it matches an expected value?
- atomic.LoadInt64
- atomic.AddInt64
- atomic.StoreInt64
- atomic.CompareAndSwapInt64 (Correct answer)
Correct answer: atomic.CompareAndSwapInt64
`atomic.CompareAndSwapInt64` atomically compares the current value with `old` and, if equal, sets it to `new`, returning whether the swap occurred.
Question 27: Why is `chan struct{}` preferred over `chan bool` for signaling in Go?
- struct{} channels are unbuffered by default
- struct{} has faster sends
- struct{} consumes zero bytes, minimizing memory overhead (Correct answer)
- bool channels do not support close
Correct answer: struct{} consumes zero bytes, minimizing memory overhead
`struct{}` is an empty type with zero size, so a `chan struct{}` uses no memory for the values themselves, making it the most efficient signal channel.
Question 28: What is a directional channel type in Go?
- A channel that sends in order
- A bidirectional buffered channel
- A channel restricted to send-only or receive-only operations (Correct answer)
- A channel with a fixed direction in memory
Correct answer: A channel restricted to send-only or receive-only operations
Directional channels like `chan<- int` (send-only) and `<-chan int` (receive-only) restrict operations for safer API design.
Question 29: What keyword is used to embed a type anonymously in a struct?
- Anonymous
- embed
- Just the type name without a field name (Correct answer)
- include
Correct answer: Just the type name without a field name
Anonymous (embedded) fields are declared with just the type name (and no explicit field name), e.g., `type S struct { T }` embeds `T` in `S`.
Question 30: What is a done channel pattern used for?
- Signal goroutines to stop working and exit (Correct answer)
- Measure goroutine performance
- Limit channel buffer size
- Synchronize goroutine start times
Correct answer: Signal goroutines to stop working and exit
A done channel (typically `chan struct{}`) is closed to broadcast a cancellation signal to multiple goroutines watching it.
Question 31: What does `runtime.GOMAXPROCS(n)` do when called with `n > 1`?
- Disables the garbage collector
- Sets the maximum number of OS threads executing Go code simultaneously (Correct answer)
- Increases goroutine priority
- Limits goroutine stack size
Correct answer: Sets the maximum number of OS threads executing Go code simultaneously
`runtime.GOMAXPROCS(n)` sets the maximum number of OS threads that can execute user-level Go code simultaneously, enabling true parallelism.
Go Programming Skills Assessment
This Go programming skills assessment evaluates a developer's proficiency in the Go language, covering core syntax, concurrency patterns, interfaces, error handling, standard library usage, and testing. Modeled after industry skills tests such as HackerRank's Go Basic and Intermediate certifications, this timed assessment is used to validate hands-on Go development competency for professional roles.
Exam Rules
- You can skip questions and return to them later
- Flag questions for review before submitting
- No feedback shown until you submit the entire exam
- Unanswered questions count as wrong — answer everything
- 10 pretest questions are mixed in and don't affect your score
- Timer auto-submits when time runs out
- Your progress is auto-saved every 30 seconds