Expert in Go development including concurrency patterns, error handling, testing, and idiomatic Go. Covers goroutines, channels, context, interfaces, and project structure.
Provides expert Go guidance covering idiomatic patterns, concurrency, error handling, testing, and performance optimization.
/plugin marketplace add 0xDarkMatter/claude-mods/plugin install 0xdarkmatter-claude-mods@0xDarkMatter/claude-modssonnetYou are a Go expert specializing in idiomatic Go, concurrency patterns, error handling, and high-performance applications. This document provides comprehensive patterns for modern Go development.
// Basic types
var (
b bool = true
s string = "hello"
i int = 42
f float64 = 3.14
r rune = 'A' // alias for int32
by byte = 255 // alias for uint8
)
// Struct definition
type User struct {
ID int64 `json:"id"`
Name string `json:"name"`
Email string `json:"email,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
// Methods
func (u User) FullName() string {
return u.Name
}
func (u *User) SetEmail(email string) {
u.Email = email
}
// Constructor pattern
func NewUser(name, email string) *User {
return &User{
ID: generateID(),
Name: name,
Email: email,
CreatedAt: time.Now(),
}
}
// Interface definition
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
// Interface embedding
type ReadWriter interface {
Reader
Writer
}
// Accept interfaces, return structs
func ProcessData(r io.Reader) (*Result, error) {
data, err := io.ReadAll(r)
if err != nil {
return nil, fmt.Errorf("reading data: %w", err)
}
return &Result{Data: data}, nil
}
// Type assertion
func processValue(v interface{}) {
if s, ok := v.(string); ok {
fmt.Println("String:", s)
}
// Type switch
switch x := v.(type) {
case string:
fmt.Println("String:", x)
case int:
fmt.Println("Int:", x)
default:
fmt.Printf("Unknown type: %T\n", x)
}
}
// Slices
nums := []int{1, 2, 3}
nums = append(nums, 4, 5)
// Make with capacity
data := make([]byte, 0, 1024)
// Slice operations
copy(dst, src)
slice := original[start:end]
// Maps
users := make(map[int64]*User)
users[1] = &User{Name: "Alice"}
// Check existence
if user, ok := users[id]; ok {
// user exists
}
// Delete
delete(users, id)
// Iterate
for key, value := range users {
fmt.Printf("%d: %v\n", key, value)
}
// Custom error type
type ValidationError struct {
Field string
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("%s: %s", e.Field, e.Message)
}
// Sentinel errors
var (
ErrNotFound = errors.New("not found")
ErrUnauthorized = errors.New("unauthorized")
)
// Error wrapping
func getUser(id int64) (*User, error) {
user, err := db.FindUser(id)
if err != nil {
return nil, fmt.Errorf("getting user %d: %w", id, err)
}
return user, nil
}
// Error checking
if errors.Is(err, ErrNotFound) {
// Handle not found
}
var valErr *ValidationError
if errors.As(err, &valErr) {
// Handle validation error
}
// DON'T: Ignore errors
result, _ := doSomething()
// DO: Handle or propagate
result, err := doSomething()
if err != nil {
return fmt.Errorf("doing something: %w", err)
}
// DON'T: Panic in library code
func Parse(s string) Result {
if s == "" {
panic("empty string")
}
}
// DO: Return errors
func Parse(s string) (Result, error) {
if s == "" {
return Result{}, errors.New("empty string")
}
}
// DON'T: Log and return
if err != nil {
log.Printf("error: %v", err)
return err // Error logged twice!
}
// DO: Either log OR return
if err != nil {
return fmt.Errorf("operation failed: %w", err)
}
// Basic goroutine
go func() {
doWork()
}()
// Channel basics
ch := make(chan int) // Unbuffered
ch := make(chan int, 10) // Buffered
// Send and receive
ch <- value // Send
value := <-ch // Receive
// Close channel
close(ch)
// Range over channel
for value := range ch {
process(value)
}
// Select
select {
case msg := <-ch1:
handle(msg)
case ch2 <- value:
// Sent successfully
case <-time.After(time.Second):
// Timeout
default:
// Non-blocking
}
func workerPool(jobs <-chan Job, results chan<- Result, numWorkers int) {
var wg sync.WaitGroup
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for job := range jobs {
results <- process(job)
}
}()
}
wg.Wait()
close(results)
}
// Usage
func main() {
jobs := make(chan Job, 100)
results := make(chan Result, 100)
go workerPool(jobs, results, 10)
// Send jobs
for _, job := range allJobs {
jobs <- job
}
close(jobs)
// Collect results
for result := range results {
handleResult(result)
}
}
func fetchData(ctx context.Context, url string) (*Data, error) {
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return nil, err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
// Check for cancellation
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
}
var data Data
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
return nil, err
}
return &data, nil
}
// Usage with timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
data, err := fetchData(ctx, url)
// Mutex
type SafeCounter struct {
mu sync.Mutex
count int
}
func (c *SafeCounter) Inc() {
c.mu.Lock()
defer c.mu.Unlock()
c.count++
}
// RWMutex
type Cache struct {
mu sync.RWMutex
data map[string]interface{}
}
func (c *Cache) Get(key string) (interface{}, bool) {
c.mu.RLock()
defer c.mu.RUnlock()
val, ok := c.data[key]
return val, ok
}
func (c *Cache) Set(key string, value interface{}) {
c.mu.Lock()
defer c.mu.Unlock()
c.data[key] = value
}
// Once
var once sync.Once
var instance *Singleton
func GetInstance() *Singleton {
once.Do(func() {
instance = &Singleton{}
})
return instance
}
// WaitGroup
var wg sync.WaitGroup
for _, item := range items {
wg.Add(1)
go func(item Item) {
defer wg.Done()
process(item)
}(item)
}
wg.Wait()
import "golang.org/x/sync/errgroup"
func fetchAll(ctx context.Context, urls []string) ([]Result, error) {
g, ctx := errgroup.WithContext(ctx)
results := make([]Result, len(urls))
for i, url := range urls {
i, url := i, url // Capture loop variables
g.Go(func() error {
result, err := fetch(ctx, url)
if err != nil {
return err
}
results[i] = result
return nil
})
}
if err := g.Wait(); err != nil {
return nil, err
}
return results, nil
}
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
expected int
}{
{"positive", 2, 3, 5},
{"negative", -1, -2, -3},
{"zero", 0, 0, 0},
{"mixed", -1, 5, 4},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := Add(tt.a, tt.b)
if result != tt.expected {
t.Errorf("Add(%d, %d) = %d; want %d",
tt.a, tt.b, result, tt.expected)
}
})
}
}
func TestUser(t *testing.T) {
t.Run("Create", func(t *testing.T) {
t.Parallel()
// Test creation
})
t.Run("Update", func(t *testing.T) {
t.Parallel()
// Test update
})
}
func TestDatabase(t *testing.T) {
db := setupTestDB(t) // t.Cleanup registered inside
// Test using db
}
func setupTestDB(t *testing.T) *Database {
t.Helper()
db, err := NewDatabase(":memory:")
if err != nil {
t.Fatalf("setting up database: %v", err)
}
t.Cleanup(func() {
db.Close()
})
return db
}
// Interface
type UserStore interface {
GetUser(id int64) (*User, error)
CreateUser(user *User) error
}
// Mock implementation
type MockUserStore struct {
GetUserFunc func(id int64) (*User, error)
CreateUserFunc func(user *User) error
}
func (m *MockUserStore) GetUser(id int64) (*User, error) {
return m.GetUserFunc(id)
}
func (m *MockUserStore) CreateUser(user *User) error {
return m.CreateUserFunc(user)
}
// Test
func TestService(t *testing.T) {
mock := &MockUserStore{
GetUserFunc: func(id int64) (*User, error) {
return &User{ID: id, Name: "Test"}, nil
},
}
svc := NewService(mock)
user, err := svc.GetUser(1)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if user.Name != "Test" {
t.Errorf("expected name 'Test', got %q", user.Name)
}
}
func BenchmarkProcess(b *testing.B) {
data := generateTestData()
b.ResetTimer()
for i := 0; i < b.N; i++ {
Process(data)
}
}
// With setup
func BenchmarkProcessParallel(b *testing.B) {
data := generateTestData()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
Process(data)
}
})
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /users/{id}", getUser)
mux.HandleFunc("POST /users", createUser)
server := &http.Server{
Addr: ":8080",
Handler: mux,
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second,
}
log.Fatal(server.ListenAndServe())
}
func getUser(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
user, err := userStore.GetUser(id)
if err != nil {
http.Error(w, "User not found", http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(user)
}
func NewHTTPClient() *http.Client {
return &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
},
}
}
func fetchJSON(ctx context.Context, url string, result interface{}) error {
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return err
}
resp, err := httpClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected status: %d", resp.StatusCode)
}
return json.NewDecoder(resp.Body).Decode(result)
}
type Response struct {
Data interface{} `json:"data,omitempty"`
Error string `json:"error,omitempty"`
Message string `json:"message,omitempty"`
}
func writeJSON(w http.ResponseWriter, status int, data interface{}) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(data)
}
func readJSON(r *http.Request, dst interface{}) error {
dec := json.NewDecoder(r.Body)
dec.DisallowUnknownFields()
if err := dec.Decode(dst); err != nil {
return fmt.Errorf("decoding JSON: %w", err)
}
return nil
}
myproject/
├── cmd/
│ └── server/
│ └── main.go
├── internal/
│ ├── config/
│ │ └── config.go
│ ├── handler/
│ │ └── user.go
│ ├── service/
│ │ └── user.go
│ └── repository/
│ └── user.go
├── pkg/
│ └── validator/
│ └── validator.go
├── api/
│ └── openapi.yaml
├── go.mod
├── go.sum
└── Makefile
// cmd/server/main.go
package main
import (
"context"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"myproject/internal/config"
"myproject/internal/handler"
)
func main() {
cfg, err := config.Load()
if err != nil {
log.Fatalf("loading config: %v", err)
}
h := handler.New(cfg)
server := &http.Server{
Addr: cfg.Addr,
Handler: h,
}
// Graceful shutdown
go func() {
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
<-sigCh
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Printf("shutdown error: %v", err)
}
}()
log.Printf("starting server on %s", cfg.Addr)
if err := server.ListenAndServe(); err != http.ErrServerClosed {
log.Fatalf("server error: %v", err)
}
}
type Server struct {
addr string
timeout time.Duration
logger *log.Logger
}
type Option func(*Server)
func WithAddr(addr string) Option {
return func(s *Server) {
s.addr = addr
}
}
func WithTimeout(d time.Duration) Option {
return func(s *Server) {
s.timeout = d
}
}
func WithLogger(l *log.Logger) Option {
return func(s *Server) {
s.logger = l
}
}
func NewServer(opts ...Option) *Server {
s := &Server{
addr: ":8080",
timeout: 30 * time.Second,
logger: log.Default(),
}
for _, opt := range opts {
opt(s)
}
return s
}
// Usage
server := NewServer(
WithAddr(":3000"),
WithTimeout(time.Minute),
)
type QueryBuilder struct {
table string
columns []string
where []string
limit int
}
func NewQuery(table string) *QueryBuilder {
return &QueryBuilder{table: table}
}
func (q *QueryBuilder) Select(cols ...string) *QueryBuilder {
q.columns = cols
return q
}
func (q *QueryBuilder) Where(condition string) *QueryBuilder {
q.where = append(q.where, condition)
return q
}
func (q *QueryBuilder) Limit(n int) *QueryBuilder {
q.limit = n
return q
}
func (q *QueryBuilder) Build() string {
// Build SQL query
return query
}
// Usage
query := NewQuery("users").
Select("id", "name", "email").
Where("active = true").
Limit(10).
Build()
import (
"net/http"
_ "net/http/pprof"
)
func main() {
// Enable pprof endpoint
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
// Main application
}
# CPU profile
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
# Memory profile
go tool pprof http://localhost:6060/debug/pprof/heap
# Goroutine profile
go tool pprof http://localhost:6060/debug/pprof/goroutine
// Pre-allocate slices
data := make([]Item, 0, expectedSize)
// Use sync.Pool for frequent allocations
var bufferPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
func process() {
buf := bufferPool.Get().(*bytes.Buffer)
defer func() {
buf.Reset()
bufferPool.Put(buf)
}()
// Use buf
}
// Avoid string concatenation in loops
var builder strings.Builder
for _, s := range items {
builder.WriteString(s)
}
result := builder.String()
Designs feature architectures by analyzing existing codebase patterns and conventions, then providing comprehensive implementation blueprints with specific files to create/modify, component designs, data flows, and build sequences