golang-patterns
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 vetandgolangci-lintpass - Tests use
-raceflag - No goroutine leaks (use errgroup or WaitGroup)