Loading...
Loading...
Go programming language skill for writing idiomatic Go code, code review, error handling, testing, concurrency, security, and program design. Use when writing Go code, reviewing Go PRs, debugging Go tests, fixing Go errors, designing Go APIs, implementing security-sensitive code, handling user input, authentication, sessions, cryptography, or asking about Go best practices. Covers table-driven tests, error wrapping, goroutine patterns, interface design, generics, iterators, stdlib patterns up to Go 1.26, and OWASP security practices.
npx skill4agent add gonzaloserrano/gopilot gopilotbytes.Buffersync.Mutexcontinuehttp.Clienthttp.HTTPClientFoo()GetFoo()Mustiota + 1fmt.Errorf("get config %s: %w", name, err)var ErrNotFound = errors.New("not found")errors.Is(err, ErrNotFound)errors.As(err, &target)errors.AsType[T]errors.Newfmt.Errorferr := errors.Join(err1, err2, err3)"connect: %w""failed to connect: %w"err != nilvar ErrNotFound = errors.New(...)type NotFoundError struct{...}errors.Iserrors.Astype temporary interface {
Temporary() bool
}
func IsTemporary(err error) bool {
te, ok := err.(temporary)
return ok && te.Temporary()
}// Bad: logs AND returns
if err != nil {
log.Printf("connect failed: %v", err)
return fmt.Errorf("connect: %w", err)
}
// Good: wrap and return; let the top-level caller log
if err != nil {
return fmt.Errorf("connect to %s: %w", addr, err)
}ctx, cancel := context.WithCancelCause(parent)
cancel(fmt.Errorf("shutdown: %w", reason))
// Later retrieve the cause
if cause := context.Cause(ctx); cause != nil {
log.Printf("context cancelled: %v", cause)
}func Min[T cmp.Ordered] (a, b T) Tcomparablecmp.Orderedtype Number interface { ~int | ~int64 | ~float64 }type Set[T comparable] = map[T]struct{}type Adder[A Adder[A]] interface { Add(A) A }anymin(a, b, c)max(a, b, c)clear(m)clear(s)new(expr)ptr := new(computeValue())func TestFoo(t *testing.T) {
tests := []struct {
name string
input string
want string
wantErr error
}{
{"EmptyInput", "", "", ErrEmpty},
{"ValidInput", "hello", "HELLO", nil},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
got, err := Foo(tc.input)
if tc.wantErr != nil {
require.ErrorIs(t, err, tc.wantErr)
return
}
require.NoError(t, err)
require.Equal(t, tc.want, got)
})
}
}func BenchmarkFoo(b *testing.B) {
for b.Loop() { // Cleaner than for i := 0; i < b.N; i++
Foo()
}
}-countrequireassertrequire.ErrorIsrequire.JSONEqrequire.YAMLEqtestdata/embed.FSt.Helper()t.Cleanup()t.Context()t.Chdir()t.ArtifactDir()t.Parallel()-racetesting/synctestimport "testing/synctest"
func TestPeriodicWorker(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
var count atomic.Int32
go func() {
for {
time.Sleep(time.Second)
count.Add(1)
}
}()
// Fake clock advances 5s instantly (no real waiting)
time.Sleep(5 * time.Second)
synctest.Wait() // wait for all goroutines to settle
require.Equal(t, int32(5), count.Load())
})
}synctest.Wait()time.Sleeptime.Aftertime.NewTimertime.NewTickersynctest.TesttimeNowerrgroup.WithContextg.Wait()sync.WaitGroup.Go()var wg sync.WaitGroup
wg.Go(func() { work() }) // Combines Add(1) + go
wg.Wait()GOEXPERIMENT=goroutineleakprofilecontext.Contextcontext.Done()sync.MutexRWMutexRWMutexsync.Oncesync.OnceFunc()sync.OnceValue()sync.OnceValues()atomicselectcontext.Done()| Operation | nil channel | closed channel |
|---|---|---|
| Send | blocks forever | panics |
| Receive | blocks forever | returns zero value |
| Close | panics | panics |
selectfor range chv, ok := <-chfor i := range 10 {
fmt.Println(i) // 0..9
}// String iterators
for line := range strings.Lines(s) { }
for part := range strings.SplitSeq(s, sep) { }
for field := range strings.FieldsSeq(s) { }
// Slice iterators
for i, v := range slices.All(items) { }
for v := range slices.Values(items) { }
for v := range slices.Backward(items) { }
for chunk := range slices.Chunk(items, 3) { }
// Map iterators
for k, v := range maps.All(m) { }
for k := range maps.Keys(m) { }
for v := range maps.Values(m) { }
// Collect iterator to slice
keys := slices.Collect(maps.Keys(m))
sorted := slices.Sorted(maps.Keys(m))
// Custom iterator
func (s *Set[T]) All() iter.Seq[T] {
return func(yield func(T) bool) {
for v := range s.items {
if !yield(v) {
return
}
}
}
}var _ http.Handler = (*MyHandler)(nil)make([]User, 0, len(ids))var t []stringt := []string{}[]slices.Clone(items)strings.Cut(s, "/")strings.Splitvar items []Item; items = append(items, newItem)type Option func(*Config)WithXOption...Optioncmp.Or(a, b, c)cmp.Or(cfg.Port, envPort, 8080)func Foo(ctx context.Context, ...)http.Server{}ReadTimeoutWriteTimeouthttp.ListenAndServedefer resp.Body.Close()*http.Client// Method-based routing with path patterns
mux.HandleFunc("POST /items/create", createHandler)
mux.HandleFunc("GET /items/{id}", getHandler)
mux.HandleFunc("GET /files/{path...}", serveFiles) // Greedy wildcard
// Extract path values
func getHandler(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
}import "net/http"
handler := http.CrossOriginProtection(myHandler)
// Rejects non-safe cross-origin requests using Fetch metadataroot, err := os.OpenRoot("/var/data")
if err != nil {
return err
}
f, err := root.Open("file.txt") // Can't escape /var/dataruntime.AddCleanup(obj, func() { cleanup() })SetFinalizerslog.Info("msg", "key", value, "key2", value2)logger := slog.With("service", "api")slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}))err != nil// WRONG: could execute f.Name() before err check in Go 1.21-1.24
f, err := os.Open("file")
name := f.Name()
if err != nil { return }
// CORRECT: check immediately
f, err := os.Open("file")
if err != nil { return }
name := f.Name()time.TickerStop()nilnilvar err error = (*MyError)(nil)err != nilinit()# .golangci.yml
linters:
enable:
- errcheck # Unchecked errors
- govet # Suspicious constructs
- staticcheck # Static analysis
- unused # Unused code
- gosimple # Simplifications
- ineffassign # Ineffectual assignments
- typecheck # Type checking
- gocritic # Opinionated checks
- gofumpt # Stricter gofmt
- misspell # Spelling
- nolintlint # Malformed //nolint directives
- wrapcheck # Errors from external packages wrapped
- errorlint # errors.Is/As usage
linters-settings:
govet:
enable-all: true
gocritic:
enabled-tags: [diagnostic, style, performance]golangci-lint run # Lint current module
golangci-lint run --fix # Auto-fix where possible
golangci-lint run --timeout 5m # Increase timeout for large codebasesmake helpmake lintmake checkmake testmake buildgo build ./...go test -v -race ./...golangci-lint rungo fix ./...gofmt -w .goimports -w .go mod tidy# Collect profile
go test -cpuprofile=default.pgo
# PGO automatically enabled if default.pgo exists in main package
go build # Uses default.pgo
# Typical 2-7% performance improvementhtml/templateos.OpenRootcrypto/randcrypto/rand.Text()InsecureSkipVerify = falsecrypto/randmath/randhttp.CrossOriginProtectionos.OpenRoot| Tool | Purpose | Command |
|---|---|---|
| gosec | Security scanner | |
| govulncheck | Vulnerability scanner | |
| trivy | Container/dep scanner | |