What Go is
TipBuilds are fast, and one program compiles for many operating systems and processors.
Asked in interviews
AskedWhat is Go and what are its main characteristics?implements keyword.TipBuilds are fast, and one program compiles for many operating systems and processors.
Asked in interviews
AskedWhat is Go and what are its main characteristics?x := 10val, err := f()var name string0, false, "", and nil for pointers, slices, maps, channels and functions.Tip:= works only inside functions. The compiler rejects an unused local variable.
Trap:= in an inner block makes a new variable that shadows the outer one.
bool, string, sized ints, float64, complex128. byte is uint8 and rune is int32.float64(i)strconv.Itoa(42) strconv.Atoi("123") iotaconst Pi = 3.14159Sunday = iotaTipGo never converts types on its own. A float converted to an int drops its fraction.
Trapstring(65) gives "A", not "65". Go reads the number as a code point.
x, then change itp := &x*p = 21p := new(int)new a starting value (1.26+)p := new(42)make(map[string]int)TipPass a pointer to change the caller's variable. Returning a pointer to a local variable is safe.
TrapDereferencing a nil pointer panics, and so does the first write to a map made with new.
[5]int is a fixed value, copied whole. []int is a pointer, a length and a capacity.s = append(s, x)append to copyd := a[:2:2]TrapA small slice of a huge array keeps the whole array in memory. Keep a copy from slices.Clone instead.
v, ok := m[key]delete(m, key)strings.Cut(s, "=")+var b strings.BuilderTiplen(s) counts bytes, not characters. Keys must be comparable, and map order is not specified.
TrapA nil map can be read but panics on write. Concurrent writes need a sync.Mutex.
breakfor x < 10 { }for { }for i, v := range sfor i := range 10for k := range maps.Keys(m)TipA switch stops after the first match unless you write fallthrough. An if can start with err := f();.
TrapBefore Go 1.22, closures in a loop shared one variable. Now each iteration has its own.
func f() (int, error)func sum(n ...int) intsum(nums...)TipInside, n is an ordinary slice. Functions are also values, so you can return closures.
TrapSpreading passes the slice itself, not a copy, so the function can change the caller's elements.
defer f.Close()panic("bad state")r := recover()TipDefers run last in, first out. defer fmt.Println(x) prints the value x had at that line.
TrapOne goroutine can't recover another's panic. An unrecovered panic in a goroutine you start crashes the whole program.
if err != nilfmt.Errorf("load: %w", err)errors.Is(err, ErrNotFound)errors.As(err, &target)errors.AsType[*MyErr](err) func (e *E) Error() stringTipAdd Unwrap() error when your type wraps a cause. Handle each error once.
TrapWrapping makes the inner error part of your API, so wrap on purpose.
Person{Name: "Alice"}dog.Name workstype Dog struct{ Animal }func (r Rect) Area()func (r *Rect) Scale()TipIf one method needs a pointer receiver, give all the type's methods one.
TrapDog is not an Animal and can't be passed as one. Code inside Animal still calls Animal.Speak.
anyinterface{}s, ok := i.(string)switch v := i.(type)TipGo favors small interfaces, often with one method, such as io.Reader. Define them where you use them.
Trapi.(string) with no ok panics if i holds anything else.
error functionreturn nilTrapNever keep a *MyError in a variable you later return as error. Every caller then sees a failure.
Asked in interviews
AskedWhy is an interface holding a nil pointer not equal to nil in Go?func F[T comparable](s []T)func (s S) M[T any](x T)TipUse generics when code is the same for every type, and an interface when behavior differs.
TrapThe reflect package is slower and turns type errors into run-time panics. NumField on a non-struct panics.
mainNewUserService(store, log)TrapPackage-level variables and init hide what each part needs and make tests share state.
Asked in interviews
AskedHow do you handle dependency injection in Go?go worker(id, jobs)TipEach starts with a few KB of stack. Since Go 1.25, the GOMAXPROCS default respects a container's CPU limit on Linux.
Trapmain does not wait for goroutines. Coordinate them with channels or a sync.WaitGroup.
Asked in interviews
AskedWhat are goroutines and how do they work?With no buffer, a send waits for a receiver. With a buffer of 3, three sends finish at once and the fourth waits.
make(chan int)make(chan int, 5)chan<- int<-chan intclose(ch)v, ok := <-chcase <-time.After(d): A default case makes a select non-blocking.TipA buffer doesn't fix a slow consumer. It only delays the moment the sender blocks.
TrapSending on a closed channel panics. Sending to or receiving from a nil channel blocks forever.
for job := range jobsclose(jobs)heap.Pop(pq)TipA dispatcher pops from container/heap. Raise a job's priority as it waits, or low-priority work can starve.
TrapSend to the workers outside the queue's lock. Otherwise a full channel blocks every producer.
context.WithTimeout(ctx, d)defer cancel()case <-ctx.Done():return ctx.Err()TipPass it as the first parameter, never in a struct. Cancelling a parent cancels every child.
TrapGive WithValue a private key type, not a string, or packages can collide. Never use it for optional parameters.
Asked in interviews
AskedWhat is thecontext package and how do you use it?mu.Lock()mu.RLock()wg.Wait()wg.Go(f)once.Do(f)sync.MapFor write-once keys, or separate keys per goroutine. Otherwise use a map and a mutex.go test -racevar n atomic.Int64n.Add(1)go statements, once.Do and atomics.TipThe race detector reports only code paths that actually run.
Trapcounter++ is a read, an add and a write, so two goroutines can lose an update.
mux.HandleFunc("GET /u/{id}", h)r.PathValue("id") func(http.Handler) http.Handlerlogging(auth(mux))signal.NotifyContext(ctx, os.Interrupt)srv.Shutdown(ctx) Tipmain must wait until Shutdown returns, or it cuts off requests. Handlers must be safe for concurrent use.
TrapA bare ListenAndServe sets no timeouts. In production, build an http.Server with Read set.
validate:"required,email"validate.Struct(req) http.MaxBytesReader(w, r.Body, n)LIMIT $1 OFFSET $2WHERE id > $1 ORDER BY id LIMIT $2TrapOffset reads and skips every earlier row, so deep pages get slow. New rows also shift the pages.
rate.NewLimiter(r, b)limiter.Allow()limiter.Wait(ctx) TipKeep one limiter per client. Several instances share counters in Redis.
TrapTrust X-Forwarded-For only from your own proxy, or a client can fake a new IP on every request.
Asked in interviews
AskedHow do you implement rate limiting in Go?argon2.IDKey(pw, salt, t, m, p, n)govulncheck ./...TipTake salts from crypto/rand, never math/rand. Compare secrets with subtle..
TrapCheck a JWT's signing method first. Otherwise an attacker can sign an HS256 token with your public RSA key as the secret.
Asked in interviews
AskedWhat security practices do you apply when building a Go web API?json.Marshal(p)json.Unmarshal(data, &p)json.NewDecoder(r.Body) json:"name,omitempty"TrapOnly exported fields are encoded, the ones that start with an upper-case letter.
Asked in interviews
AskedHow do you work with JSON in Go?os.ReadFile(name) bufio.NewScanner(f) now.Format("2006-01-02") time.Parse(layout, s)==a.Equal(b)TipA bufio.Writer holds small writes. Call Flush and check its error before the file closes.
TrapA layout is the reference time Mon Jan 2 15:04:05 MST 2006 as you want it shown. YYYY doesn't work.
sql.Open("pgx", dsn)WHERE id = $1for rows.Next()rows.Scan(&u.ID) TipAfter the loop, check rows.Err(). Query returns sql.ErrNoRows when nothing matches.
Trap*sql.DB is a connection pool, not one connection. Open it once and share it. Open may not connect, so call PingContext.
Asked in interviews
AskedHow do you work with databases in Go?os.Args[1:]flag.Int("n", 1, "help")flag.Parse()os.Getenv("PORT") slog.NewJSONHandler(w, nil)log.Println("started") Traplog.Fatal exits at once, without running deferred calls.
init() runsBefore main. Imports finish first, then package variables, then init.go get github.com/lib/pq@v1.10.7 go mod tidygo.sum holds the hashes.TrapA major version of two or more must appear in the module path, as in /v2.
_test.go filefunc TestAdd(t *testing.T)go test -cover ./...t.Run(name, fn)for b.Loop()Tipt.Errorf marks the test failed and continues, and t.Fatalf stops it. Fuzz tests are FuzzXxx(f *testing.F).
Asked in interviews
AskedHow do you write unit tests in Go?//go:build linux || darwingo build -tags sqlite// +build linux//go:generate stringer -type=Colorgo generate ./...TipGo has no macros. Generated code is ordinary Go the compiler checks, while reflection is slower and unchecked.
Trapgo build never runs go generate. Run it yourself and commit the output.
GOGC=100GOMEMLIMIT=1GiBgo build -gcflags=-munsafe.String(unsafe.SliceData(b), len(b))TrapNever modify bytes that back a string. Strings are immutable and other code may share them.
import _ "net/http/pprof" go tool pprof <host>/debug/pprof/profile /debug/pprof/goroutine?debug=2 , or send SIGQUIT.goroutineleak profile reports goroutines blocked on something no running code can reach.TipA goroutine leak is one blocked forever. Give each goroutine an exit path, such as a select on ctx.Done().
TrapKeep the pprof port private, because it exposes internals.
SET key token NX PX 30000singleflight.Group TrapIf work outlasts the expiry, another process gets the lock while you still think you hold it.
tracer.Start(ctx, "db.load")Trapspan. doesn't mark a span as failed. Also call span..
Nothing matches. Try a shorter word, or clear the search.
With Pro, you can:
Already have Pro? Sign in