thecodex.expert · The Codex Family of Knowledge
Snippets

Go Snippets

13 idiomatic Go patterns — copy, paste, adapt.

Go 1.21+ 13 snippets Verified
Gogoroutines.go
Goroutines and WaitGroup
package main

import (
    "fmt"
    "sync"
    "sync/atomic"
)

func main() {
    var wg sync.WaitGroup
    var counter atomic.Int64  // thread-safe counter

    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            counter.Add(1)
            fmt.Printf("worker %d done\n", id)
        }(i)  // pass i as argument — avoids closure capture bug
    }

    wg.Wait()
    fmt.Println("Total:", counter.Load())  // 10

    // Mutex for shared non-atomic state
    var mu sync.Mutex
    shared := make(map[string]int)

    var wg2 sync.WaitGroup
    for _, word := range []string{"go", "go", "rust", "go"} {
        wg2.Add(1)
        go func(w string) {
            defer wg2.Done()
            mu.Lock()
            shared[w]++
            mu.Unlock()
        }(word)
    }
    wg2.Wait()
    fmt.Println(shared)  // map[go:3 rust:1]
}
Gochannels.go
Channels, select, and done pattern
package main

import (
    "fmt"
    "time"
)

func producer(done <-chan struct{}) <-chan int {
    ch := make(chan int)
    go func() {
        defer close(ch)  // close signals: no more values
        for i := 0; ; i++ {
            select {
            case <-done:
                return  // cancelled
            case ch <- i:
                time.Sleep(50 * time.Millisecond)
            }
        }
    }()
    return ch
}

func main() {
    done := make(chan struct{})

    ch := producer(done)

    // Read 5 values then cancel
    for i := 0; i < 5; i++ {
        fmt.Println(<-ch)  // 0, 1, 2, 3, 4
    }
    close(done)  // signal producer to stop

    // Select with timeout
    timeout := time.After(100 * time.Millisecond)
    for {
        select {
        case v, ok := <-ch:
            if !ok { fmt.Println("channel closed"); return }
            fmt.Println("got:", v)
        case <-timeout:
            fmt.Println("timed out")
            return
        }
    }
}
Goerrors.go
Error handling: wrap, Is, As
package main

import (
    "errors"
    "fmt"
)

// Sentinel error for comparison with errors.Is
var ErrNotFound = errors.New("not found")

// Custom error type for errors.As
type ValidationError struct {
    Field   string
    Message string
}

func (e *ValidationError) Error() string {
    return fmt.Sprintf("validation: %s: %s", e.Field, e.Message)
}

func findUser(id int) (string, error) {
    if id <= 0 {
        return "", &ValidationError{Field: "id", Message: "must be positive"}
    }
    if id > 100 {
        return "", fmt.Errorf("findUser %d: %w", id, ErrNotFound)  // wrap
    }
    return fmt.Sprintf("user%d", id), nil
}

func main() {
    _, err := findUser(999)
    if errors.Is(err, ErrNotFound) {  // unwraps the error chain
        fmt.Println("user not found")
    }

    _, err2 := findUser(-1)
    var ve *ValidationError
    if errors.As(err2, &ve) {  // extract concrete type from chain
        fmt.Printf("invalid field: %s — %s\n", ve.Field, ve.Message)
    }

    // Multi-error (Go 1.20)
    err3 := errors.Join(ErrNotFound, fmt.Errorf("timeout"))
    fmt.Println(errors.Is(err3, ErrNotFound))  // true
}
Gohttp_server.go
HTTP server with middleware and JSON
package main

import (
    "encoding/json"
    "log"
    "net/http"
    "time"
)

type User struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

// Middleware: wraps http.Handler
func logging(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        next.ServeHTTP(w, r)
        log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start))
    })
}

func jsonResponse(w http.ResponseWriter, status int, data any) {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(status)
    json.NewEncoder(w).Encode(data)
}

func userHandler(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case http.MethodGet:
        jsonResponse(w, http.StatusOK, User{ID: 1, Name: "Alice"})
    case http.MethodPost:
        var u User
        if err := json.NewDecoder(r.Body).Decode(&u); err != nil {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }
        jsonResponse(w, http.StatusCreated, u)
    default:
        http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
    }
}

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/users", userHandler)

    srv := &http.Server{
        Addr:         ":8080",
        Handler:      logging(mux),
        ReadTimeout:  5 * time.Second,
        WriteTimeout: 10 * time.Second,
        IdleTimeout:  60 * time.Second,
    }
    log.Fatal(srv.ListenAndServe())
}
Gointerfaces.go
Interfaces and implicit satisfaction
package main

import (
    "fmt"
    "math"
)

// Interface: any type with these methods satisfies it — no implements keyword
type Shape interface {
    Area() float64
    Perimeter() float64
}

type Circle struct{ Radius float64 }
type Rect   struct{ W, H float64 }

func (c Circle) Area() float64      { return math.Pi * c.Radius * c.Radius }
func (c Circle) Perimeter() float64 { return 2 * math.Pi * c.Radius }
func (r Rect) Area() float64        { return r.W * r.H }
func (r Rect) Perimeter() float64   { return 2 * (r.W + r.H) }

func printShape(s Shape) {
    fmt.Printf("Area: %.2f, Perimeter: %.2f\n", s.Area(), s.Perimeter())
}

func totalArea(shapes []Shape) float64 {
    total := 0.0
    for _, s := range shapes { total += s.Area() }
    return total
}

func main() {
    shapes := []Shape{Circle{5}, Rect{4, 6}}
    for _, s := range shapes { printShape(s) }
    fmt.Printf("Total area: %.2f\n", totalArea(shapes))

    // Type assertion
    var s Shape = Circle{3}
    if c, ok := s.(Circle); ok {
        fmt.Println("Radius:", c.Radius)
    }

    // Type switch
    for _, sh := range shapes {
        switch v := sh.(type) {
        case Circle: fmt.Println("circle r=", v.Radius)
        case Rect:   fmt.Println("rect", v.W, "x", v.H)
        }
    }
}
Gogenerics.go
Generics (Go 1.18+)
package main

import "fmt"

// Map applies f to every element
func Map[T, U any](s []T, f func(T) U) []U {
    result := make([]U, len(s))
    for i, v := range s {
        result[i] = f(v)
    }
    return result
}

// Filter returns elements where f returns true
func Filter[T any](s []T, f func(T) bool) []T {
    var result []T
    for _, v := range s {
        if f(v) { result = append(result, v) }
    }
    return result
}

// Reduce folds to a single value
func Reduce[T, U any](s []T, init U, f func(U, T) U) U {
    acc := init
    for _, v := range s { acc = f(acc, v) }
    return acc
}

// Number constraint
type Number interface { ~int | ~int64 | ~float64 }

func Sum[T Number](s []T) T {
    var total T
    for _, v := range s { total += v }
    return total
}

// Generic stack
type Stack[T any] struct{ items []T }
func (s *Stack[T]) Push(v T)         { s.items = append(s.items, v) }
func (s *Stack[T]) Pop() (T, bool) {
    if len(s.items) == 0 { var zero T; return zero, false }
    v := s.items[len(s.items)-1]
    s.items = s.items[:len(s.items)-1]
    return v, true
}

func main() {
    nums := []int{1, 2, 3, 4, 5}
    doubled := Map(nums, func(n int) int { return n * 2 })
    evens   := Filter(nums, func(n int) bool { return n%2 == 0 })
    total   := Reduce(nums, 0, func(acc, n int) int { return acc + n })
    fmt.Println(doubled, evens, total)  // [2 4 6 8 10] [2 4] 15
}
Gocontext.go
Context: cancellation and values
package main

import (
    "context"
    "fmt"
    "time"
)

type ctxKey string

const requestIDKey ctxKey = "requestID"

func doWork(ctx context.Context) error {
    // Check cancellation at each major step
    select {
    case <-ctx.Done():
        return ctx.Err()  // context.Canceled or DeadlineExceeded
    default:
    }

    // Simulate work
    time.Sleep(10 * time.Millisecond)

    // Extract value from context
    if id, ok := ctx.Value(requestIDKey).(string); ok {
        fmt.Println("Request ID:", id)
    }
    return nil
}

func main() {
    // WithTimeout: auto-cancel after duration
    ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
    defer cancel()  // always call — frees resources even if timeout fires

    // Attach values for request-scoped data (not for optional parameters)
    ctx = context.WithValue(ctx, requestIDKey, "req-abc-123")

    if err := doWork(ctx); err != nil {
        fmt.Println("Work failed:", err)
    }

    // WithCancel: manual cancellation
    ctx2, cancel2 := context.WithCancel(context.Background())
    go func() {
        time.Sleep(50 * time.Millisecond)
        cancel2()  // signal cancellation
    }()
    <-ctx2.Done()
    fmt.Println("ctx2 cancelled:", ctx2.Err())
}
Goslices_maps.go
Slices, maps, and Go 1.21 stdlib additions
package main

import (
    "fmt"
    "maps"
    "slices"
)

func main() {
    // Slice operations
    s := []int{5, 3, 1, 4, 2}
    slices.Sort(s)                       // [1 2 3 4 5] — in-place
    idx, found := slices.BinarySearch(s, 3)
    fmt.Println(idx, found)              // 2 true

    s2 := slices.Clone(s)                // deep copy
    s2 = slices.Delete(s2, 1, 3)        // remove indices 1..2
    fmt.Println(s2)                      // [1 4 5]

    // slices.Collect (Go 1.23): collect iterator to slice
    // all := slices.Collect(maps.Keys(m))

    // Map operations (Go 1.21)
    m := map[string]int{"a": 1, "b": 2, "c": 3}
    m2 := maps.Clone(m)

    maps.DeleteFunc(m2, func(k string, v int) bool {
        return v < 2  // delete entries where value < 2
    })
    fmt.Println(m2)  // map[b:2 c:3]

    // Check equality
    fmt.Println(maps.Equal(m, maps.Clone(m)))  // true

    // Frequency counter — common idiom
    words := []string{"go", "go", "rust", "go"}
    freq := make(map[string]int)
    for _, w := range words { freq[w]++ }

    // Safe map read: comma-ok idiom
    count, ok := freq["rust"]
    fmt.Println(count, ok)  // 1 true
    missing, ok := freq["python"]
    fmt.Println(missing, ok)  // 0 false
}
Goembedding.go
Struct embedding and interface composition
package main

import "fmt"

type Logger struct{ prefix string }
func (l Logger) Log(msg string) { fmt.Printf("[%s] %s\n", l.prefix, msg) }

type Server struct {
    Logger                 // embedded: Logger's methods promoted to Server
    Host string
    Port int
}

func (s *Server) Start() {
    s.Log(fmt.Sprintf("starting on %s:%d", s.Host, s.Port))  // promoted method
}

// Interface composition
type Reader interface { Read() string }
type Writer interface { Write(s string) }
type ReadWriter interface {
    Reader
    Writer
}

// Struct satisfying composed interface
type Buffer struct{ data string }
func (b *Buffer) Read() string      { return b.data }
func (b *Buffer) Write(s string)    { b.data += s }

func copy(src Reader, dst Writer) {
    dst.Write(src.Read())
}

func main() {
    s := Server{Logger: Logger{"APP"}, Host: "0.0.0.0", Port: 8080}
    s.Start()        // [APP] starting on 0.0.0.0:8080
    s.Log("ready")   // promoted: s.Logger.Log

    b1 := &Buffer{data: "hello"}
    b2 := &Buffer{}
    copy(b1, b2)
    fmt.Println(b2.Read())  // hello
}
Gotesting.go
Table-driven tests and benchmarks
package math_test

import (
    "testing"
    "time"
)

func Add(a, b int) int { return a + b }
func Fib(n int) int {
    if n <= 1 { return n }
    return Fib(n-1) + Fib(n-2)
}

func TestAdd(t *testing.T) {
    tests := []struct {
        name     string
        a, b     int
        expected int
    }{
        {"positive", 1, 2, 3},
        {"negative", -1, -2, -3},
        {"zero", 0, 0, 0},
        {"mixed", 5, -3, 2},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got := Add(tt.a, tt.b)
            if got != tt.expected {
                t.Errorf("Add(%d,%d) = %d; want %d", tt.a, tt.b, got, tt.expected)
            }
        })
    }
}

// Benchmark: go test -bench=.
func BenchmarkFib20(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Fib(20)
    }
}

// Parallel test
func TestAddParallel(t *testing.T) {
    t.Parallel()  // run alongside other parallel tests
    if Add(2, 3) != 5 { t.Fatal("wrong") }
}

// Test with cleanup
func TestWithSetup(t *testing.T) {
    t.Cleanup(func() { /* teardown */ })
    t.Log("running")
}
Goio_patterns.go
io.Reader/Writer and functional options
package main

import (
    "bytes"
    "fmt"
    "io"
    "strings"
)

// io.Reader/Writer work with any source/sink — files, network, memory
func processReader(r io.Reader) (int, error) {
    buf := make([]byte, 4096)
    total := 0
    for {
        n, err := r.Read(buf)
        total += n
        if err == io.EOF { break }
        if err != nil { return total, err }
    }
    return total, nil
}

func main() {
    // String as Reader
    r := strings.NewReader("Hello, World!")
    n, _ := processReader(r)
    fmt.Println("bytes:", n)  // 13

    // Buffer as both Reader and Writer
    var buf bytes.Buffer
    fmt.Fprintf(&buf, "count: %d", 42)
    io.WriteString(&buf, " and more")
    fmt.Println(buf.String())  // "count: 42 and more"

    // Functional options pattern
    type ServerConfig struct {
        host    string
        port    int
        timeout int
    }
    type Option func(*ServerConfig)

    withHost := func(h string) Option { return func(c *ServerConfig) { c.host = h } }
    withPort := func(p int) Option    { return func(c *ServerConfig) { c.port = p } }

    newServer := func(opts ...Option) *ServerConfig {
        cfg := &ServerConfig{host: "localhost", port: 8080, timeout: 30}
        for _, o := range opts { o(cfg) }
        return cfg
    }

    srv := newServer(withHost("0.0.0.0"), withPort(9090))
    fmt.Printf("%+v\n", *srv)
}
Gojson_struct_tags.go
JSON encoding with struct tags
package main

import (
    "encoding/json"
    "fmt"
    "time"
)

type User struct {
    ID        int       `json:"id"`
    Name      string    `json:"name"`
    Email     string    `json:"email,omitempty"` // omit if zero value
    Password  string    `json:"-"`               // never serialise
    CreatedAt time.Time `json:"created_at"`
    Tags      []string  `json:"tags,omitempty"`
}

func main() {
    u := User{ID: 1, Name: "Alice", CreatedAt: time.Now(), Password: "secret"}
    data, _ := json.Marshal(u)
    fmt.Println(string(data))
    // {"id":1,"name":"Alice","created_at":"2026-..."}
    // email and tags omitted (empty); password omitted (-)

    // Pretty print
    pretty, _ := json.MarshalIndent(u, "", "  ")
    fmt.Println(string(pretty))

    // Decode
    raw := `{"id":2,"name":"Bob","email":"bob@example.com","tags":["admin"]}`
    var u2 User
    json.Unmarshal([]byte(raw), &u2)
    fmt.Println(u2.Name, u2.Tags)  // Bob [admin]

    // Decode to map when schema is unknown
    var m map[string]any
    json.Unmarshal([]byte(raw), &m)
    fmt.Println(m["name"])  // Bob
}
Godefer_panic.go
defer, panic, and recover
package main

import (
    "fmt"
    "os"
)

// defer: runs when function returns — cleanup, logging, unlock
func readFile(path string) error {
    f, err := os.Open(path)
    if err != nil { return err }
    defer f.Close()  // guaranteed to run — even on early return or error

    // Multiple defers run LIFO (last in, first out)
    defer fmt.Println("done reading")
    defer fmt.Println("closing file")

    // ... read from f
    return nil
}

// recover: catch panics in goroutines
func safeDiv(a, b int) (result int, err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("recovered panic: %v", r)
        }
    }()
    return a / b, nil  // panics if b == 0
}

// Named return values work with defer
func withNamedReturn() (n int, err error) {
    defer func() {
        if err != nil {
            n = -1  // can modify named return values in defer
        }
    }()
    // ... do work
    return 42, nil
}

func main() {
    result, err := safeDiv(10, 0)
    fmt.Println(result, err)  // 0 recovered panic: runtime error: integer divide by zero

    result2, _ := safeDiv(10, 2)
    fmt.Println(result2)  // 5
}
Go referenceGo overview · Learn Go
← TypeScript Rust snippets →
Everything Go in one place — learning paths, reference, playground, and more. Go Hub →