6 knowledge files: rust, SOLID/DRY, ast-grep, karpathy, golang, caveman 65 chunks ingested to log/knowledge/learn/latest.jsonl Chunks on ## headings, SHA256 dedup, configurable chunk size
4.3 KiB
4.3 KiB
Go (Golang) Skills
Core Idioms
- Accept interfaces, return structs.
- Errors are values — check them explicitly.
if err != nil { return err }. - Don't panic in library code. Reserve panic for truly unrecoverable situations.
- Zero values are useful —
var m map[string]intis nil butvar s []intis usable.
Error Handling
- Wrap errors with context:
fmt.Errorf("failed to open %s: %w", path, err). - Sentinel errors:
var ErrNotFound = errors.New("not found"). Check witherrors.Is(err, ErrNotFound). - Custom error types:
type ValidationError struct { Field, Message string }. Check witherrors.As(). - Never ignore errors:
_ = doSomething()is a code smell. At minimum, log it.
Concurrency
- "Don't communicate by sharing memory; share memory by communicating." — use channels.
go func()launches goroutine. Always ensure goroutines terminate (context, done channel).sync.WaitGroupto wait for goroutine completion.sync.Mutexwhen channels are overkill (protecting a counter, map).context.Contextfor cancellation, timeouts, and request-scoped values. Always first parameter.errgroup.Groupfor parallel tasks with error propagation.
Channel Patterns
ch := make(chan T)unbuffered (synchronous).make(chan T, n)buffered.- Fan-out: multiple goroutines read from one channel.
- Fan-in: multiple channels merged into one via select.
- Pipeline: chain of stages connected by channels.
selectwithcase <-ctx.Done():for cancellation.- Close channels from sender side only. Never close from receiver.
Interfaces
- Interfaces are satisfied implicitly — no
implementskeyword. - Keep interfaces small:
io.Readerhas one method.io.ReadWriteClosercomposes three. - Define interfaces where they're used, not where they're implemented.
interface{}(orany) is a code smell — prefer generics or specific interfaces.- Type assertions:
v, ok := i.(ConcreteType). Type switch:switch v := i.(type) { ... }.
Generics (Go 1.18+)
func Map[T, U any](s []T, f func(T) U) []U— generic function.- Constraints:
comparable,~int | ~float64, custom interface constraints. - Use generics for data structures and utility functions, not business logic.
Project Structure
cmd/
myapp/main.go # entrypoint
internal/ # private packages
domain/ # business logic, no external deps
repository/ # data access
handler/ # HTTP handlers
pkg/ # public library code
internal/enforced by Go compiler — cannot be imported outside module.- One package per directory. Package name = directory name.
Testing
func TestFoo(t *testing.T)— test functions.- Table-driven tests:
tests := []struct{ name string; input int; want int }{ ... }. t.Run(name, func(t *testing.T) { ... })for subtests.t.Parallel()for concurrent test execution.testify/assertfor cleaner assertions.testify/mockfor mocking.httptest.NewServer()for HTTP integration tests.- Benchmarks:
func BenchmarkFoo(b *testing.B) { for i := 0; i < b.N; i++ { ... } }.
HTTP Server
http.HandlerFuncwraps functions as handlers.- Middleware pattern:
func Logging(next http.Handler) http.Handler. - Use
chiorechofor routing. Stdlibhttp.ServeMuximproved in Go 1.22. - Always set timeouts:
srv := &http.Server{ReadTimeout: 5*time.Second, WriteTimeout: 10*time.Second}. - Graceful shutdown:
signal.Notify+srv.Shutdown(ctx).
Performance
pproffor CPU/memory profiling:go tool pprof http://localhost:6060/debug/pprof/profile.sync.Poolfor reducing GC pressure on frequently allocated objects.- Pre-allocate slices:
make([]T, 0, expectedLen). - String building:
strings.Buildernot+concatenation. - Avoid interface boxing in hot paths.
Common Gotchas
- Loop variable capture in goroutines (fixed in Go 1.22, but still common in older code).
- Nil interface vs nil pointer:
var p *MyType = nil; var i MyInterface = p; i != nilis TRUE. - Maps are not safe for concurrent access — use
sync.Maporsync.RWMutex. - Slice append may or may not create a new backing array — never hold stale slice references.
deferevaluates arguments immediately, runs function at return.init()runs beforemain()— avoid side effects, prefer explicit initialization.