skip to content

Go (Golang)

4 roadmaps1,712 questionsupdated

Go is what teams reach for when they want fast, simple network services that ship as a single static binary: concurrency built into the language, a collector tuned for very short pauses, and a standard library that already speaks HTTP and JSON. Interviewers probe it hard because the language is small enough that the interesting questions are about semantics and runtime behavior rather than syntax.

on this pageshow

guide

overview

~2 min

Go interviews test whether you know what the language does underneath its small syntax. The grammar is quick to learn, so the opening questions go straight to semantics: what assigning a slice or a struct actually copies, which methods a pointer carries that a plain value does not, why an interface holding a nil pointer is not itself nil. The longest stretch is usually concurrency — goroutines, channels, `select`, the `sync` package and `context` — because a Go hire is expected to write a worker that is bounded, cancellable and free of races with nothing but the standard library. Errors come next, since returning them as values makes failure handling part of every function's design. Senior rounds move below the language to the scheduler, the garbage collector and escape analysis, and then out to production: reading a profile, sizing memory and CPU inside a container, stopping a server without dropping requests. The hub follows those seams. The language itself is [Core Language and Type System](/topics/lang-go-core-language), [Errors and Failure Design](/topics/lang-go-errors) and [Idioms and API Design](/topics/lang-go-idioms). [Concurrency](/topics/lang-go-concurrency) has its own section, and [Runtime Machinery](/topics/lang-go-runtime-internals) explains what the scheduler and collector do beneath it. The standard library splits by job: [Text, Time and Collections](/topics/lang-go-values), [Operating System Access](/topics/lang-go-os-io), [Data Encoding and Storage](/topics/lang-go-data-encoding), [Network Services and Clients](/topics/lang-go-http-services) and [Security and Cryptography](/topics/lang-go-security). The working-engineer layer is [Automated Testing](/topics/lang-go-testing), [Modules, Build and Toolchain](/topics/lang-go-tooling-ecosystem), [Performance and Diagnostics](/topics/lang-go-performance) and [Service Telemetry](/topics/lang-go-telemetry), and the escape hatches — reflection, `unsafe`, cgo — sit in [Low-Level and Foreign Code](/topics/lang-go-interop). Learn the core language and errors first: nearly every later answer assumes you can say what a copy shares and how a failure travels back up the call stack. Concurrency comes next, then the HTTP section, which is where most Go roles spend their day and where goroutines, contexts and errors meet in one handler. Pick up testing and the toolchain alongside, because interviewers expect you to reach for the built-in tools rather than name a third-party one. Leave runtime internals and performance for last unless the role is senior or infrastructure-facing; they only make sense once you know which behaviour they explain.

primer

### Everything is passed by value — know what the value holds Assignment, argument passing and `range` all copy. What the copy shares depends on the type: an array or a struct copies its contents, shallowly, while a slice, map, channel, function or interface is a small descriptor that refers to data stored elsewhere, so two copies see the same elements. A large share of junior and mid-level questions — surprising `append` results, methods whose writes seem to vanish, a map mutated through a "copy" — reduce to this one rule. ### Zero values are meant to be usable Every variable starts at its type's zero value, and idiomatic types are designed so that value works: an empty `bytes.Buffer`, an unlocked `sync.Mutex`, a nil slice you can append to. Remember the exceptions, because interviewers do: writing into a nil map panics, and sending or receiving on a nil channel blocks forever. A constructor exists when the zero value cannot be made valid, not out of habit. ### Interfaces are satisfied implicitly and kept small A type satisfies an interface by having its methods; there is no `implements` clause. That lets the consumer own the interface: a package declares the two or three methods it needs, and any type with them fits, including types written before the interface existed. The standard library's one-method interfaces — `io.Reader`, `io.Writer`, `error`, `http.Handler` — are the model to imitate. Method sets decide what fits, and a method declared on a pointer receiver belongs to `*T`, not to `T`. ### Errors are values, and the caller decides A function that can fail hands back an `error` alongside its result, and the caller checks it before trusting anything else. Wrapping adds context on the way up while keeping the original inspectable, so a caller can still match a sentinel or an error type several layers down. `panic` is for programmer mistakes and states the program cannot continue from; using it as a general exception mechanism is a design interviewers expect you to reject. ### Concurrency is cheap to start and your job to stop A goroutine starts with a stack of a few kilobytes, so launching one is easy; knowing how it ends is the real skill. Channels hand data from one goroutine to another, mutexes guard shared state, and `context.Context` carries cancellation and deadlines down the call tree. Nothing stops a goroutine from outside: each one has to watch for its own exit signal, and one that blocks forever is a leak that usually goes unnoticed until memory climbs. The race detector finds unsynchronised access, but only on paths a test or a run actually executed. ### The runtime is part of your program Every binary carries a scheduler that multiplexes goroutines onto OS threads and a concurrent, non-moving garbage collector designed for short pauses. The compiler's escape analysis decides whether a value lives on the stack or the heap, so allocation is a property of how the code is shaped rather than of `new` or `&`. Senior questions ask you to connect a symptom — latency spikes, steady memory growth, idle CPUs under load — to one of these mechanisms, and then to the setting that adjusts it: `GOGC`, `GOMEMLIMIT` or `GOMAXPROCS`. ### Simplicity is a design position Go leaves out inheritance, exceptions and operator overloading, went without generics until 1.18, and ships one formatter and one build command. Interviewers probe whether you can defend those choices and write code that follows the conventions they produce: short names in small scopes, composition through embedding, accepting interfaces and returning concrete types, a small exported surface. An abstraction that fights the language tends to read as unfamiliarity with it. ### The standard library is the default dependency HTTP servers and clients, JSON, SQL access, TLS, structured logging, testing and profiling all ship with the toolchain, and interviews assume you know them. Expect to be asked what `net/http` or `database/sql` does for you and what it leaves to you — timeouts, pool sizes, closing bodies and rows — more often than which third-party package you would install.

Goroutine
A function running concurrently under the Go runtime's scheduler, started with the go statement; far cheaper than an OS thread and with no handle the caller can use to stop it.
Channel
A typed conduit that goroutines send values into and receive values from; unbuffered channels synchronise sender and receiver, buffered ones decouple them up to a fixed capacity.
select statement
A statement that waits on several channel operations at once and proceeds with whichever becomes ready; a default case makes it non-blocking.
Zero value
The value a variable holds before anything is assigned: 0, false, empty string, or nil for pointers, slices, maps, channels, functions and interfaces.
Slice
A three-part value of pointer, length and capacity describing a window into an underlying array; copying the slice copies the description, not the elements.
Method set
The methods callable through a given type; for a pointer type it includes methods with value receivers as well as pointer receivers, which decides interface satisfaction.
Interface value
A pair of dynamic type and dynamic value; it compares equal to nil only when both halves are empty, not merely when the stored pointer is nil.
Embedding
Declaring a field by type alone so the outer type gains the inner type's fields and methods; composition with promoted members, not inheritance.
Type parameter
A placeholder type in a generic function or type, restricted by a constraint interface that lists the methods or underlying types it allows.
Sentinel error
A package-level error variable, such as io.EOF, that callers compare against to recognise one specific condition.
Error wrapping
Building a new error that carries an earlier one inside it, so errors.Is and errors.As can search the chain while the message gains context.
Context
The context.Context value passed first through a call chain, carrying a cancellation signal, an optional deadline and a few request-scoped values.
Data race
Two goroutines touching the same memory at once, at least one writing, with no synchronisation between them; the result is undefined, not merely stale.
Happens-before
The ordering relation in Go's memory model that decides when a write in one goroutine is guaranteed visible to a read in another.
Race detector
Instrumentation enabled with the race flag on build and test commands that reports conflicting unsynchronised accesses when they actually occur during a run.
GMP model
The scheduler's structure: goroutines (G) run on OS threads (M), which must hold a processor (P); the number of Ps is set by GOMAXPROCS.
Escape analysis
The compiler pass that decides whether a variable can stay in its function's stack frame or must move to the garbage-collected heap.
GOGC
The garbage collector's growth setting: how much the heap may grow, as a percentage of live data, before the next cycle starts. The default is 100.
GOMEMLIMIT
A soft memory limit for the Go runtime, added in 1.19, that makes the collector work harder as total memory approaches the given size.
Module
A versioned collection of packages defined by a go.mod file, which names its path, its Go language version and its requirements.
Minimal version selection
Go's dependency rule: build with the lowest version of each module that satisfies every requirement in the graph, so builds are reproducible without a solver.
Table-driven test
A test that loops over a slice of named cases and runs each as a subtest, the standard shape for Go unit tests.
pprof
The profiling format and tool for Go: CPU, heap, goroutine, block and mutex profiles collected from the runtime and explored with go tool pprof.
cgo
The mechanism for calling C from Go and back; it needs a C toolchain, gives up the pure-Go static build and makes each crossing slower than a Go call.

The sections stack around a small core. Value semantics, method sets and interfaces from the core language are what every other section is written in. [Interfaces and Implicit Satisfaction](/topics/lang-go-core-language-interfaces) explains why a file, a network connection and a compressed stream can all be handed to the same function, and much of [Operating System Access](/topics/lang-go-os-io) and [Data Encoding and Storage](/topics/lang-go-data-encoding) is that one idea applied to readers and writers. Errors follow the same pattern: `error` is itself an interface, so [Wrapping and Inspection](/topics/lang-go-errors-wrapping) rests on the same dynamic type checks as any other interface value. Concurrency is where the language meets the runtime. Goroutines and channels are language features; what makes them cheap, and what makes them misbehave under load, lives in the [Goroutine Scheduler (GMP)](/topics/lang-go-runtime-internals-scheduler) and the [Garbage Collector](/topics/lang-go-runtime-internals-gc). [Performance and Diagnostics](/topics/lang-go-performance) is the same machinery seen from outside — profiles and traces are the runtime reporting on itself — so a tuning question is often a runtime question in disguise. `context.Context` is the thread through the service-facing sections. A server gives each request a context; handlers pass it to database calls, outbound requests and log records; cancellation then travels from a client that hung up down to the query it started. [Network Services and Clients](/topics/lang-go-http-services), [Relational Access](/topics/lang-go-data-encoding-sql), [Distributed Tracing Hooks](/topics/lang-go-telemetry-tracing) and [Termination Handling](/topics/lang-go-os-io-lifecycle) all depend on it, which is why a function that quietly drops its caller's context counts as a defect in review. Tooling and testing surround everything. The module system fixes which code builds, `go vet` and the race detector catch what the compiler accepts, and the testing package supplies the tables, benchmarks and fuzz targets that prove the rest. The escape hatches in [Low-Level and Foreign Code](/topics/lang-go-interop) are best understood by what each costs: reflection trades away compile-time type checks, `unsafe` trades away memory safety, and cgo trades away the pure-Go static build and cheap calls. A short function where several of these meet: ```go func fetchAll(ctx context.Context, urls []string) ([]Result, error) { ctx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() results := make(chan Result, len(urls)) for _, u := range urls { go func() { results <- fetch(ctx, u) }() } out := make([]Result, 0, len(urls)) for range urls { select { case r := <-results: out = append(out, r) case <-ctx.Done(): return out, fmt.Errorf("fetch all: %w", ctx.Err()) } } return out, nil } ``` The channel has a slot for every result, so goroutines still running after an early return can complete their send and exit instead of leaking. `select` lets the deadline win over a slow fetch, `%w` keeps the context's error matchable with `errors.Is` further up, and since Go 1.22 each iteration declares a fresh `u`, so the closures no longer share one variable. The design assumes `fetch` honours its context: if it ignores it, the timeout returns control to the caller while the work carries on in the background.

  1. Core Language and Type System →

    Value copies, method sets, interfaces and slices are assumed by every other section; most junior questions start here.

  2. Errors and Failure Design →

    Error values, wrapping and the panic boundary appear in almost every function you write or review, so learn them early.

  3. Concurrency →

    The longest stretch of most rounds: goroutine lifetimes, channels and select, the sync package and context cancellation.

  4. Network Services and Clients →

    Where most Go jobs live, and where concurrency, context and error handling meet in real handlers and clients.

  5. Automated Testing →

    Interviewers expect the built-in testing package: table-driven cases, test doubles through interfaces, benchmarks and the race detector.

  6. Runtime Machinery →

    Once the language feels routine, learn the scheduler, collector and memory layout that senior questions and performance work rest on.

  • Calling append without keeping its result, or keeping two slices over one array: a later append can overwrite elements the other slice still reads. See Slices, Maps and Structs.

  • Returning a typed nil pointer as an error: the interface still holds a type, so err != nil is true and the caller sees a failure that never happened.

  • Starting a goroutine with no way to end it: without a context, a closed channel or a done signal it can block forever, and leaked goroutines hold memory silently.

  • Treating a data race as harmless because tests passed: racy programs get no useful guarantee, and the race detector sees only the paths that ran.

  • Writing to a plain map from several goroutines without a lock: the runtime may detect it and abort the whole process with a fatal error that recover cannot stop.

  • Using panic and recover as exceptions for ordinary failures: reviewers expect error returns, and recover only works inside a deferred call on the panicking goroutine.

  • Matching errors with == or by message text: once any layer wraps with %w, equality stops finding the cause, while errors.Is and errors.As still reach it.

  • Shipping an http.Server or http.Client with its zero-value timeouts: a slow or silent peer can then hold a connection and a goroutine indefinitely.

  • Storing a context.Context in a struct field or passing nil: pass it explicitly as the first argument, and use context.TODO() while the right one is unclear.

  • Declaring an interface beside its only implementation just to mock it: Go convention lets the consumer define the small interface it needs.

  • Running in a memory-limited container without GOMEMLIMIT: the collector paces itself on heap growth, not on the container limit, so the process can be killed for exceeding it.

  • Deferring a Close inside a loop: deferred calls run when the function returns, so every file or row set stays open until the loop's function exits.

This guide assumes Go 1.25. Go keeps a strong compatibility promise, so most answers read the same on releases a few years older, but interviewers still ask about the milestones that changed everyday code: - **1.11 and 1.16** — modules arrived in 1.11 and became the default mode in 1.16, ending the GOPATH workflow. - **1.13** — `errors.Is`, `errors.As` and the `%w` verb made wrapping part of the standard library. - **1.14** — the scheduler gained asynchronous preemption, so a tight loop without function calls can no longer stall other goroutines or the collector. - **1.18** — generics, fuzzing in `go test`, and workspaces. - **1.19** — the soft memory limit, `GOMEMLIMIT`, and a revised memory model document. - **1.21** — `log/slog`, the `slices`, `maps` and `cmp` packages, the `min`, `max` and `clear` built-ins, and the `toolchain` line in go.mod. - **1.22** — loop variables became per-iteration, `range` over integers, and method and wildcard patterns in the standard `ServeMux`. - **1.23** — range-over-function iterators and the `iter` package. - **1.25** — `GOMAXPROCS` began respecting a container's CPU limit on Linux, and `testing/synctest` became stable. The loop-variable change is the one that still confuses candidates reading older code: ```go for _, v := range values { v := v // needed before 1.22: otherwise every goroutine shared one v go use(v) } ``` From 1.22 in a module that declares that version or later, each iteration already has its own `v`, and the copy line is redundant.

Go was created at Google and is developed as an open-source project. Interviewers expect you to place it in three settings. In **cloud infrastructure**, it is the language of much of the container and orchestration tooling — Docker, Kubernetes, Terraform and Prometheus are written in it — so platform and SRE roles often read and extend Go code before they write any. In **backend services**, it competes with Java and Kotlin on the JVM, with Node.js, and with Python: a single static binary, fast startup and a modest memory footprint against larger ecosystems and heavier frameworks. For **command-line tools**, cross-compiling a dependency-free binary for each platform is a common reason to choose it. The comparison that comes up most at senior level is with **Rust**: both compile to native code, but Go keeps a garbage collector and a deliberately small language, while Rust removes the collector and enforces memory safety at compile time at the cost of a steeper language. A good answer names that trade-off without ranking them. Around the standard library, expect to recognise a few common third-party names: routers such as chi or gin, the pgx driver for PostgreSQL, testify for assertions, gRPC with Protocol Buffers for service-to-service calls, and `golang.org/x/sync` for `errgroup`. Interviewers rarely test them in depth; they want to know you can tell when the standard library is enough.

explore

report an issue with this guide →

questions

1,712 · 15 sections

In Go, what is the difference between an array `[5]int` and a slice `[]int`?

level: juniorimportance: must knowfreq 88%
basics
~20 s

An array's length is part of its type, and assigning or passing one copies every element. A slice is a resizable view onto a backing array, carrying a length and a capacity; copying a slice shares that array.

open as a page

What does Go copy when you assign a struct that has slice and map fields?

level: juniorimportance: must knowfreq 78%
basics
~20 s

Assignment copies a struct field by field. Number, string, bool and array fields become independent, but a slice, map or pointer field copies only the reference, so both structs still read and write the same underlying data.

open as a page

In Go, what is the difference between a keyed struct literal and a positional one?

level: juniorimportance: must knowfreq 68%
basics
~20 s

A keyed struct literal names each field and may omit fields, so order does not matter. A positional literal must supply every field in declaration order, so reordering fields silently changes what each value means.

open as a page

In Go, how do you distinguish a missing map key from one whose stored value is zero?

level: juniorimportance: must knowfreq 78%
basics
~20 s

Use the two-value comma-ok form: v, ok := m[key]. ok is true only when the key is present. A one-value lookup returns the value type's zero value for a missing key, so 0, an empty string or false cannot tell you which happened.

open as a page

Go passes every argument by value — how do you write a function that modifies the caller's struct?

level: juniorimportance: must knowfreq 88%
basics
~20 s

Pass a pointer. A function parameter of type Player receives a copy, so writes to it die with the call. Declare the parameter as *Player, call it with &pl, and write p.HP = 40 — Go dereferences the selector for you.

open as a page

In Go, when does a send block on make(chan int) versus make(chan int, 3)?

level: juniorimportance: must knowfreq 82%
basics
~20 s

A send on a channel made with make(chan int) blocks until another goroutine is ready to receive. With make(chan int, 3) the send returns immediately while the buffer holds fewer than three values, and blocks only once it is full.

open as a page

When you send a struct value on a Go channel, does the receiver get a copy or the sender's original?

level: juniorimportance: must knowfreq 65%
basics
~20 s

A channel send copies the value. The receiver gets its own copy of the struct, so later writes by the sender are invisible. The copy is shallow: pointer, slice and map fields still refer to the same underlying data.

open as a page

What does close(ch) do to a Go channel, and what do receivers see afterwards?

level: juniorimportance: must knowfreq 82%
basics
~20 s

close(ch) marks a Go channel as finished. Receives stop blocking: they deliver any values still buffered, then return the element type's zero value with ok false, and a for range loop over the channel exits.

open as a page

What does a nil channel in Go do to a goroutine that sends or receives on it?

level: juniorimportance: must knowfreq 62%
basics
~10 s

Both operations block forever. A send on a nil channel and a receive from a nil channel park the goroutine permanently, because no counterparty can ever exist. Closing a nil channel panics instead.

open as a page

What does a `default` case do in a Go `select` statement?

level: juniorimportance: must knowfreq 68%
basics
~20 s

A default case makes the select non-blocking. If no other case can proceed at that instant, Go runs default immediately instead of waiting. Without a default, the select parks the goroutine until one of its cases is ready.

open as a page

Why does ranging over the same Go map twice give the entries in a different order?

level: juniorimportance: must knowfreq 68%
basics
~20 s

Go's runtime starts every map iteration at a randomly chosen position, so map order is undefined and changes from loop to loop. For stable output, copy the keys into a slice, sort it, and index the map in that order.

open as a page

Why must you write s = append(s, x) in Go instead of just calling append(s, x)?

level: juniorimportance: must knowfreq 85%
basics
~20 s

append returns a new slice value and never updates the slice you passed in. If the backing array has no spare room, append allocates a bigger array, so only the returned value is guaranteed to see the appended element.

open as a page

What three fields does a Go slice header hold at runtime, and what does each mean?

level: juniorimportance: must knowfreq 78%
basics
~20 s

A Go slice value is three words: a pointer to the first element it covers in a backing array, a length, and a capacity. The elements live in that array, not inside the slice value.

open as a page

What does a Go string value hold at runtime, and what does assigning one to another variable copy?

level: juniorimportance: must knowfreq 62%
basics
~20 s

A Go string value is a two-word header: a pointer to an array of bytes plus a length. Assigning or passing a string copies only that header (16 bytes on a 64-bit platform), never the text it points at.

open as a page

Why does `defer f.Close()` inside a Go for loop keep every file open until the function returns?

level: juniorimportance: must knowfreq 62%
basics
~20 s

Go's defer is scoped to the function call, not to the block or the loop iteration. Every trip through the loop registers one more deferred Close against the same frame, and none of them run until the enclosing function returns.

open as a page

What is a sentinel error in Go, and how do you declare one so callers can detect it?

level: juniorimportance: must knowfreq 70%
basics
~20 s

A sentinel error is one package-level error value, such as var ErrNotFound = errors.New("not found"), that a package returns for a specific condition. Callers detect that condition by matching a returned error against that exported value.

open as a page

How do you define a custom Go error type that carries structured fields a caller can read?

level: juniorimportance: must knowfreq 72%
basics
~20 s

Declare a struct holding the data and give it an Error() string method, normally on a pointer receiver. Any type with that method is usable as an error, and callers read the exported fields off the concrete value.

open as a page

What does ctx.Err() return after a context is cancelled versus after its deadline passes?

level: juniorimportance: must knowfreq 72%
basics
~10 s

ctx.Err() returns nil while the context is still live, context.Canceled once a cancel function has been called, and context.DeadlineExceeded once the context's deadline has passed. Match them with errors.Is, not with ==.

open as a page

Why is io.EOF returned by a Read call treated as a normal end of input, not a failure?

level: juniorimportance: must knowfreq 82%
basics
~20 s

io.EOF is a sentinel error the io.Reader contract uses to say the stream is finished, so nothing went wrong. Callers detect it, stop reading and return success; they never log it or pass it on as a fault.

open as a page

Given an error from os.Open, how do you check that the file does not exist?

level: juniorimportance: must knowfreq 76%
basics
~10 s

Use errors.Is(err, fs.ErrNotExist). os.Open returns a *fs.PathError wrapping the operating system's error, so comparing the returned error directly against fs.ErrNotExist is always false; errors.Is unwraps the chain and finds the sentinel.

open as a page

Go's testing package has no assertEqual - how do you compare a value against an expected one in a test?

level: juniorimportance: must knowfreq 70%
basics
~20 s

You compare with ordinary Go code: == for comparable types, reflect.DeepEqual or slices.Equal for composites. On a mismatch call t.Errorf and print both values, conventionally the value you got first, then the value you wanted.

open as a page

What does declaring `package foo_test` in a _test.go file change versus declaring `package foo`?

level: juniorimportance: must knowfreq 58%
basics
~20 s

A _test.go file declaring package foo compiles into the package itself and can use its unexported identifiers. One declaring package foo_test compiles as a separate package that must import foo and sees only its exported API.

open as a page

Why do Go tests keep fixture files in a directory named testdata, and how does the go command treat it?

level: juniorimportance: must knowfreq 50%
basics
~20 s

The go command ignores directories named testdata when matching package patterns, so nothing inside is compiled or vetted. A test binary runs with its own package directory as the working directory, so a relative path like testdata/user.go.golden always resolves.

open as a page

In a Go test, what does t.TempDir() return and who deletes that directory?

level: juniorimportance: must knowfreq 58%
basics
~20 s

t.TempDir() returns the path of a fresh, empty directory created for that test. The testing package removes it automatically once the test and all of its subtests have completed, so the test never writes its own removal code.

open as a page

What does calling t.Parallel() in a Go test do, and when does that test's body actually run?

level: juniorimportance: must knowfreq 60%
basics
~20 s

t.Parallel() marks a test as safe to run alongside other tests that also call it. The call pauses the test immediately; it resumes only after its parent test function has returned, and then runs concurrently with its parallel siblings.

open as a page

Why does go/parser.ParseFile need a token.FileSet, and what does it return?

level: juniorimportance: must knowfreq 40%
basics
~20 s

go/parser.ParseFile returns an *ast.File, the syntax tree of one source file, plus an error. Node positions are bare integers; the token.FileSet holds each file's name and line table, so those integers decode to file, line and column.

open as a page

What does a `replace` directive in go.mod do, and how do you point one at a local directory?

level: juniorimportance: must knowfreq 60%
basics
~20 s

A replace directive in go.mod redirects a module path to something else: either a different module at a stated version, or a directory on disk. The build then compiles that code instead of the version the proxy would serve.

open as a page

What does `go mod tidy` change in a module's go.mod, and when do you run it?

level: juniorimportance: must knowfreq 78%
basics
~20 s

go mod tidy makes the require block match the code: it adds a requirement for every module your packages import, drops requirements nothing imports any more, maintains the indirect markers, and syncs go.sum. Run it after changing imports.

open as a page

Why must a Go module's path and its import paths end in /v2 once it releases v2.0.0?

level: juniorimportance: must knowfreq 70%
basics
~20 s

Go treats each major version as a separate module. From v2 on, the module line in go.mod and every import of its packages must end in /v2, so v1 and v2 can live in one build.

open as a page

What does `go get -u ./...` do in a Go module, and how does `-u=patch` differ?

level: juniorimportance: must knowfreq 58%
basics
~20 s

go get -u ./... upgrades every module behind the packages your module imports, directly or transitively, to its newest minor or patch release. go get -u=patch caps each move at the newest patch of the minor already selected.

open as a page

What does GOTRACEBACK=all change about the output of a crashing Go program?

level: juniorimportance: must knowfreq 50%
basics
~20 s

By default a Go crash prints a stack for the goroutine that panicked. GOTRACEBACK=all makes the runtime print a stack for every user-created goroutine instead. It is an environment variable, so it costs a restart, not a rebuild.

open as a page

When you step through a plain `go build` binary, why do locals read as optimized out, and which build flags fix it?

level: juniorimportance: must knowfreq 50%
basics
~20 s

Go's compiler keeps locals in registers and inlines small calls, so the variable and the stack frame a debugger looks for do not exist at runtime. Rebuild with go build -gcflags="all=-N -l" to disable optimisation and inlining before stepping.

open as a page

In Go, how do you capture a panic's stack trace inside the deferred function that recovers it?

level: juniorimportance: must knowfreq 58%
basics
~10 s

Call runtime/debug.Stack() inside the deferred function. It returns the calling goroutine's formatted stack trace as a byte slice, still containing the frames that panicked. debug.PrintStack() does the same but writes straight to standard error.

open as a page

What has the Go runtime detected when it prints "fatal error: all goroutines are asleep - deadlock!"?

level: juniorimportance: must knowfreq 60%
basics
~20 s

Every user goroutine is parked waiting on another goroutine, with nothing runnable, no armed timer and no thread in a system call. Progress is provably impossible, so the runtime dumps every goroutine stack and exits.

open as a page

What does a "too many open files" error from net.Dial or os.Open tell you?

level: juniorimportance: must knowfreq 55%
basics
~20 s

The process has hit its RLIMIT_NOFILE ceiling on open file descriptors. Every socket, file and open HTTP response body costs one, so the cause is almost always a resource opened on some code path and never closed.

open as a page

What does Go's cmp.Compare return, and which types can you call it on?

level: juniorimportance: must knowfreq 42%
basics
~10 s

cmp.Compare returns -1 if the first argument is less, 0 if they are equal, and +1 if it is greater. It accepts any cmp.Ordered type: integers, floats, strings, and named types built on them.

open as a page

In Go's container/heap, which five methods must your type implement?

level: juniorimportance: must knowfreq 34%
basics
~20 s

container/heap.Interface embeds sort.Interface, so your type needs Len, Less and Swap, plus Push(x any) to append one element and Pop() any to remove and return the last one. Five methods, and you own the storage.

open as a page

Why does ranging over a Go map yield a different order each run, and how do you produce stable output?

level: juniorimportance: must knowfreq 78%
basics
~10 s

Go deliberately randomises map iteration, so no order is guaranteed or repeatable. For stable output, copy the keys into a slice, sort that slice, then read the map in that key order.

open as a page

What does slices.Clone(s) copy that the plain assignment b := s does not?

level: juniorimportance: must knowfreq 68%
basics
~10 s

slices.Clone allocates a new backing array and copies the elements into it, so the two slices no longer share storage. Plain assignment copies only the slice header, leaving both names pointing at one array.

open as a page

What does slices.Sort do to a slice, and which element types can it sort?

level: juniorimportance: must knowfreq 62%
basics
~20 s

slices.Sort reorders a slice in place into ascending order and returns nothing. It is generic over element types that support the less-than operator - integers, floats and strings - so no comparison callback or interface implementation is needed.

open as a page

In Go, how do you let an environment variable set a flag's default so an explicit flag still wins?

level: juniorimportance: must knowfreq 60%
basics
~20 s

Read the variable with os.LookupEnv before flag.Parse and pass its value as the default argument when you declare the flag. flag.Parse then overwrites that default only for flags that actually appeared on the command line.

open as a page

In Go, what is the difference between os.Getenv and os.LookupEnv?

level: juniorimportance: must knowfreq 70%
basics
~10 s

os.Getenv returns only the value, so an unset variable and one set to the empty string both come back as "". os.LookupEnv returns the value plus a presence boolean, keeping those two cases distinct.

open as a page

In Go's flag package, why does flag.String return a *string, and when may you read it?

level: juniorimportance: must knowfreq 70%
basics
~20 s

flag.String registers a flag before the command line has been read, so it can only hand back a pointer to storage it will fill in later. Call flag.Parse() first, then read the value as *ptr.

open as a page

Why write a config file to a temp file and os.Rename it onto the target instead of overwriting in place?

level: juniorimportance: must knowfreq 48%
basics
~20 s

Overwriting in place leaves the file half-written, so a concurrent reader can load a truncated config. Writing a complete temp file first and calling os.Rename swaps the name in one step: readers see the whole old file or the whole new one.

open as a page

What does os.ReadFile give you, and what work does it do that you would otherwise write by hand?

level: juniorimportance: must knowfreq 80%
basics
~20 s

os.ReadFile opens the named file, reads it to the end, closes it, and returns the whole contents as a []byte together with an error. Reaching end of file is not an error, so a successful read returns a nil error.

open as a page

Why does adding a String() method to a type leave json.Marshal's output unchanged?

level: juniorimportance: must knowfreq 60%
basics
~10 s

fmt.Stringer is consulted only by the fmt package. encoding/json never looks for String; it looks for json.Marshaler and then encoding.TextMarshaler, and a type with neither is encoded from its structure, field by field.

open as a page

Why does a []byte struct field marshal to a base64 string in encoding/json?

level: juniorimportance: must knowfreq 55%
basics
~20 s

JSON has no type for raw bytes, so encoding/json marshals a []byte field as a base64 string using the standard padded alphabet. A nil []byte becomes null and an empty one becomes an empty string.

open as a page

What do binary.BigEndian.Uint32 and binary.LittleEndian.Uint32 return for the bytes 00 00 01 00?

level: juniorimportance: must knowfreq 45%
basics
~10 s

binary.BigEndian.Uint32 reads the most significant byte first and returns 256. binary.LittleEndian.Uint32 reads the least significant byte first and returns 65536. Same four bytes, opposite orders, different numbers.

open as a page

Why must a gzip.Writer be closed before the file is valid, and what breaks if its Close error is dropped?

level: juniorimportance: must knowfreq 48%
basics
~20 s

A gzip.Writer buffers compressed data and writes the gzip trailer, a CRC32 plus the uncompressed length, only on Close. Skip Close and the file is truncated; ignore Close's error and a failed final write vanishes silently.

open as a page

In Go's encoding/csv, when would you use Reader.Read in a loop instead of Reader.ReadAll?

level: juniorimportance: must knowfreq 55%
basics
~20 s

ReadAll builds the whole file as one [][]string in memory and returns nil records if any row fails to parse. Read hands back one record per call and ends with io.EOF, so large or partly malformed files stay workable.

open as a page

Why must you call resp.Body.Close() on an http.Response, and where does that defer belong?

level: juniorimportance: must knowfreq 82%
basics
~20 s

An http.Response body is an open stream on a live connection; closing it releases that connection and its socket. Put defer resp.Body.Close() straight after the error check, because a failed request returns a nil response.

open as a page

What does Go's http.Client.Timeout field cover, and does it include reading the response body?

level: juniorimportance: must knowfreq 80%
basics
~20 s

http.Client.Timeout bounds one whole call: DNS, dial, TLS handshake, sending the request, any redirects, and reading the response body. The clock keeps running after Do returns, so a slow body read fails too. Zero means no timeout.

open as a page

Why does http.Client.Do return a nil error when the server replies 500?

level: juniorimportance: must knowfreq 80%
basics
~10 s

http.Client.Do reports only transport-level failures - DNS, dial, TLS, a deadline, a broken connection. A 500 is a completed HTTP exchange, so err is nil; you must check resp.StatusCode yourself and close the body.

open as a page

Does Go's http.Get follow a 302 redirect automatically, and how do you find the final URL?

level: juniorimportance: must knowfreq 48%
basics
~10 s

Go's http.Get follows redirects automatically: http.DefaultClient stops only after ten consecutive hops, so you receive the final response, not the 302. The field resp.Request.URL holds the URL of the last request actually sent.

open as a page

Why does retrying the same *http.Request send an empty body on the second attempt?

level: juniorimportance: must knowfreq 55%
basics
~20 s

A request body is a one-shot io.ReadCloser. The first Do drains it and the Transport closes it, so a second Do on the same *http.Request finds nothing left to read. Build a fresh request for every attempt.

open as a page

How do you build an AES-GCM cipher.AEAD in Go and encrypt one message with it?

level: juniorimportance: must knowfreq 50%
basics
~10 s

Pass the key to aes.NewCipher to get a cipher.Block, wrap that block with cipher.NewGCM to get a cipher.AEAD, then call Seal(dst, nonce, plaintext, additionalData). Seal returns the ciphertext with a 16-byte authentication tag appended.

open as a page

What does Go's hmac.Equal do that bytes.Equal does not, and what does it return?

level: juniorimportance: must knowfreq 45%
basics
~20 s

hmac.Equal(mac1, mac2 []byte) returns a bool and scans every byte, so its running time does not depend on the contents. bytes.Equal stops at the first differing byte, so its timing reveals how much of the input matched.

open as a page

What is the difference between sha256.Sum256 and sha256.New, and when do you use each?

level: juniorimportance: must knowfreq 52%
basics
~20 s

sha256.Sum256 hashes a byte slice you already hold and returns a [32]byte array. sha256.New returns a streaming hash.Hash you write data into and finish with Sum(nil) - use that when the input is a file or stream too large to buffer.

open as a page

How do you use `hkdf.Key` in Go to turn one master secret into a separate key per purpose?

level: juniorimportance: must knowfreq 45%
basics
~10 s

Call hkdf.Key once per purpose with a different info string each time, for example "cookie-encryption-v1" versus "url-signing-v1". Same secret, same salt, different info, and you get independent keys you never have to store.

open as a page

Why is math/rand/v2 unsafe for generating a password-reset token in Go, and what do you use instead?

level: juniorimportance: must knowfreq 62%
basics
~20 s

math/rand/v2 is a statistical generator that makes no unpredictability promise, so its output can be reconstructed no matter how it is seeded. Use crypto/rand instead: rand.Text() for a token string, or crypto/rand.Read to fill a byte slice.

open as a page

In Go's log/slog, why does a `slog.Debug` call still cost work when the logger's level is Info?

level: juniorimportance: must knowfreq 52%
basics
~20 s

Go evaluates every argument before the call runs, so work you do to build a log line happens even at a disabled level. slog only checks the level inside the call, after the arguments are boxed into interfaces.

open as a page

Which four methods does slog.Handler require, and what is each one for?

level: juniorimportance: must knowfreq 50%
basics
~20 s

slog.Handler has four methods: Enabled reports whether a level should be logged, Handle formats and writes one Record, WithAttrs returns a new handler carrying extra attributes, and WithGroup returns one that nests later keys under a name.

open as a page

What does Go's log package write by default: which stream, what prefix, and what severity?

level: juniorimportance: must knowfreq 48%
basics
~20 s

Go's log package writes to standard error through the one logger returned by log.Default(), prefixing each line with the date and time (log.LstdFlags). It has no severity levels: log.Print, log.Printf and log.Println all produce identical, unlabelled lines.

open as a page

In Go's log/slog, what does implementing the LogValuer interface on a type change about how it is logged?

level: juniorimportance: must knowfreq 38%
basics
~20 s

A type that implements LogValuer supplies a LogValue method returning a slog.Value, and slog logs that substitute instead of the value itself. Every handler sees the substitute, so a secret can be replaced with a fixed placeholder in one place.

open as a page

Should a containerised Go service's slog handler write to os.Stdout or os.Stderr?

level: juniorimportance: must knowfreq 56%
basics
~20 s

Both streams are collected by the container runtime, so the real rule is to pick one and send every record there. Most teams choose os.Stdout for the application's log stream and leave os.Stderr to the runtime's own panic output.

open as a page

In cgo, what do C.CBytes and C.GoBytes do, and who frees the C copy?

level: juniorimportance: must knowfreq 45%
basics
~10 s

C.CBytes copies a Go []byte into malloc'd C memory and returns an unsafe.Pointer you must release with C.free. C.GoBytes copies C memory back into a brand-new Go slice that the garbage collector owns.

open as a page

What is syscall.Errno, and how do you test whether an error is a specific errno such as ENOENT?

level: juniorimportance: must knowfreq 38%
basics
~20 s

syscall.Errno is an integer type (a uintptr) whose Error method makes the number itself satisfy Go's error interface. Test for a particular errno with errors.Is(err, syscall.ENOENT), which unwraps wrappers such as *os.PathError instead of matching message text.

open as a page

What do reflect.TypeOf and reflect.ValueOf return, and how do you get an ordinary Go value back?

level: juniorimportance: must knowfreq 48%
basics
~20 s

reflect.TypeOf returns a reflect.Type describing the dynamic type of whatever you pass it; reflect.ValueOf returns a reflect.Value wrapping the data itself. Value.Interface() hands the data back as an any, which you then type-assert to a concrete type.

open as a page

What does reflect.New(t) return in Go, and why do you call Elem() on the result?

level: juniorimportance: must knowfreq 34%
basics
~20 s

reflect.New(t) allocates a zero value of type t and returns a reflect.Value holding a pointer to it, exactly like new(T). Elem() follows that pointer to the value itself, which lives in addressable memory and can be filled in.

open as a page

Why does reflect.DeepEqual report a nil []string and an empty []string{} as unequal?

level: juniorimportance: must knowfreq 55%
basics
~20 s

reflect.DeepEqual requires two slices to be both nil or both non-nil before it compares length and elements. A nil slice and an empty slice fail that first check, so it reports false even though both have length zero.

open as a page

In Go, why do reviewers reject an exported interface declared beside its only implementation?

level: juniorimportance: must knowfreq 72%
basics
~20 s

Go checks interface satisfaction implicitly, so whoever needs the abstraction can declare it later. An interface written beside its only implementation adds indirection now, hides the concrete type's other methods and fields, and buys nothing.

open as a page

Why does Go compile a call whose returned error you never check?

level: juniorimportance: must knowfreq 72%
basics
~20 s

Go's compiler rejects unused variables and unused imports, but not unused return values. A call like f.Close() is a complete statement on its own, so nothing forces you to look at the error it returns.

open as a page

What is wrong with a package-level `var apiURL = os.Getenv("API_URL")` in a Go package?

level: juniorimportance: must knowfreq 68%
basics
~20 s

It runs at package initialization, before main, so nothing can supply or check the value: the package cannot report a missing setting as an error, and a test can only change it by writing to a global.

open as a page

How should a Go constructor New(cfg Config) supply defaults for fields the caller left at zero?

level: juniorimportance: must knowfreq 62%
basics
~20 s

New takes the Config by value, replaces each field still at its zero value with a named package default, and builds the object from that copy. The caller's struct is untouched, and every caller gets identical defaults.

open as a page

Why do Go libraries write `New(addr string, opts ...Option)` instead of one parameter per setting?

level: juniorimportance: must knowfreq 62%
basics
~20 s

Because callers pass only the settings they care about. Option is a function type such as func(*Client); each With... helper returns one, and New starts from a struct holding the package defaults and applies the options to it.

open as a page
Go (Golang) interview questions & primer · KataJob