golang-patterns

📁 peopleforrester/claude-dotfiles 📅 Feb 6, 2026
3
总安装量
2
周安装量
#57284
全站排名
安装命令
npx skills add https://github.com/peopleforrester/claude-dotfiles --skill golang-patterns

Agent 安装分布

amp 2
gemini-cli 2
claude-code 2
github-copilot 2
codex 2
kimi-cli 2

Skill 文档

Go Patterns

Modern Go 1.22+ patterns and best practices.

Error Handling

Wrap Errors with Context

import "fmt"

func readConfig(path string) (*Config, error) {
    data, err := os.ReadFile(path)
    if err != nil {
        return nil, fmt.Errorf("readConfig %s: %w", path, err)
    }
    // ...
}

Custom Error Types

type ValidationError struct {
    Field   string
    Message string
}

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

// Check with errors.As
var valErr *ValidationError
if errors.As(err, &valErr) {
    log.Printf("Invalid field: %s", valErr.Field)
}

Sentinel Errors

var (
    ErrNotFound     = errors.New("not found")
    ErrUnauthorized = errors.New("unauthorized")
)

// Check with errors.Is
if errors.Is(err, ErrNotFound) {
    http.Error(w, "Not found", http.StatusNotFound)
}

Concurrency

Structured Concurrency with errgroup

import "golang.org/x/sync/errgroup"

func fetchAll(ctx context.Context, urls []string) ([]Response, error) {
    g, ctx := errgroup.WithContext(ctx)
    results := make([]Response, len(urls))

    for i, url := range urls {
        g.Go(func() error {
            resp, err := fetch(ctx, url)
            if err != nil {
                return err
            }
            results[i] = resp
            return nil
        })
    }

    if err := g.Wait(); err != nil {
        return nil, err
    }
    return results, nil
}

Context for Cancellation

func longOperation(ctx context.Context) error {
    for {
        select {
        case <-ctx.Done():
            return ctx.Err()
        default:
            // Do work
        }
    }
}

Channel Patterns

// Fan-out, fan-in
func merge(channels ...<-chan int) <-chan int {
    out := make(chan int)
    var wg sync.WaitGroup
    for _, ch := range channels {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for v := range ch {
                out <- v
            }
        }()
    }
    go func() {
        wg.Wait()
        close(out)
    }()
    return out
}

Interfaces

Small Interfaces

// Good: Focused interfaces
type Reader interface {
    Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}

// Compose when needed
type ReadWriter interface {
    Reader
    Writer
}

Accept Interfaces, Return Structs

// Good: Function accepts interface
func Process(r io.Reader) error { /* ... */ }

// Good: Function returns concrete type
func NewServer(addr string) *Server { /* ... */ }

Generics (1.18+)

Type Constraints

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

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

HTTP Patterns

Middleware Chain

type Middleware func(http.Handler) http.Handler

func Chain(h http.Handler, middlewares ...Middleware) http.Handler {
    for i := len(middlewares) - 1; i >= 0; i-- {
        h = middlewares[i](h)
    }
    return h
}

func LoggingMiddleware(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))
    })
}

Tooling

Tool Purpose Command
go vet Static analysis go vet ./...
golangci-lint Meta-linter golangci-lint run
go test Testing go test -race -cover ./...
go fmt Formatting gofmt -w .

Checklist

  • Errors wrapped with context (fmt.Errorf("...: %w", err))
  • Context passed to all I/O and long operations
  • Goroutines have proper lifecycle management
  • Interfaces are small (1-3 methods)
  • go vet and golangci-lint pass
  • Tests use -race flag
  • No goroutine leaks (use errgroup or WaitGroup)