Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Senior Go developer skill covering concurrency patterns, gRPC microservices, generics, pprof optimization, and idiomatic testing.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/interfaces.md
1# Interface Design and Composition23## Small, Focused Interfaces45```go6// Single-method interfaces (idiomatic Go)7type Reader interface {8Read(p []byte) (n int, err error)9}1011type Writer interface {12Write(p []byte) (n int, err error)13}1415type Closer interface {16Close() error17}1819// Interface composition20type ReadCloser interface {21Reader22Closer23}2425type WriteCloser interface {26Writer27Closer28}2930type ReadWriteCloser interface {31Reader32Writer33Closer34}35```3637## Accept Interfaces, Return Structs3839```go40package storage4142import "io"4344// Storage is the concrete type (struct)45type Storage struct {46baseDir string47}4849// NewStorage returns a concrete type50func NewStorage(baseDir string) *Storage {51return &Storage{baseDir: baseDir}52}5354// SaveFile accepts an interface for flexibility55func (s *Storage) SaveFile(filename string, data io.Reader) error {56// Implementation can work with any Reader57// (file, network, buffer, etc.)58return nil59}6061// Usage allows dependency injection62type Uploader interface {63SaveFile(filename string, data io.Reader) error64}6566type Service struct {67uploader Uploader // Accept interface68}6970// NewService accepts interface for testing flexibility71func NewService(uploader Uploader) *Service {72return &Service{uploader: uploader}73}74```7576## io.Reader and io.Writer Patterns7778```go79import (80"io"81"strings"82)8384// Chain readers with io.MultiReader85func combineReaders() io.Reader {86r1 := strings.NewReader("Hello ")87r2 := strings.NewReader("World")88return io.MultiReader(r1, r2)89}9091// Tee reader for duplicating reads92func duplicateRead(r io.Reader, w io.Writer) io.Reader {93return io.TeeReader(r, w) // Writes to w while reading from r94}9596// Limit reader to prevent reading too much97func limitedRead(r io.Reader, n int64) io.Reader {98return io.LimitReader(r, n)99}100101// Custom Reader implementation102type UppercaseReader struct {103src io.Reader104}105106func (u *UppercaseReader) Read(p []byte) (n int, err error) {107n, err = u.src.Read(p)108for i := 0; i < n; i++ {109if p[i] >= 'a' && p[i] <= 'z' {110p[i] = p[i] - 32111}112}113return n, err114}115116// Custom Writer implementation117type CountingWriter struct {118w io.Writer119count int64120}121122func (cw *CountingWriter) Write(p []byte) (n int, err error) {123n, err = cw.w.Write(p)124cw.count += int64(n)125return n, err126}127128func (cw *CountingWriter) BytesWritten() int64 {129return cw.count130}131```132133## Embedding for Composition134135```go136import "sync"137138// Embed to extend behavior139type SafeCounter struct {140mu sync.Mutex141m map[string]int142}143144func (sc *SafeCounter) Inc(key string) {145sc.mu.Lock()146defer sc.mu.Unlock()147sc.m[key]++148}149150// Embed interface to add default behavior151type Logger interface {152Log(msg string)153}154155type NoOpLogger struct{}156157func (NoOpLogger) Log(msg string) {}158159type Service struct {160Logger // Embedded interface (default implementation can be provided)161}162163func NewService(logger Logger) *Service {164if logger == nil {165logger = NoOpLogger{} // Provide default166}167return &Service{Logger: logger}168}169170// Now Service.Log() is available171```172173## Interface Satisfaction Verification174175```go176import "io"177178// Compile-time interface verification179var _ io.Reader = (*MyReader)(nil)180var _ io.Writer = (*MyWriter)(nil)181var _ io.Closer = (*MyCloser)(nil)182183type MyReader struct{}184185func (m *MyReader) Read(p []byte) (n int, err error) {186return 0, nil187}188189type MyWriter struct{}190191func (m *MyWriter) Write(p []byte) (n int, err error) {192return len(p), nil193}194195type MyCloser struct{}196197func (m *MyCloser) Close() error {198return nil199}200```201202## Functional Options Pattern203204```go205package server206207import "time"208209type Server struct {210host string211port int212timeout time.Duration213maxConns int214enableLogger bool215}216217// Option is a functional option for configuring Server218type Option func(*Server)219220func WithHost(host string) Option {221return func(s *Server) {222s.host = host223}224}225226func WithPort(port int) Option {227return func(s *Server) {228s.port = port229}230}231232func WithTimeout(timeout time.Duration) Option {233return func(s *Server) {234s.timeout = timeout235}236}237238func WithMaxConnections(max int) Option {239return func(s *Server) {240s.maxConns = max241}242}243244func WithLogger(enabled bool) Option {245return func(s *Server) {246s.enableLogger = enabled247}248}249250// NewServer creates a server with functional options251func NewServer(opts ...Option) *Server {252// Defaults253s := &Server{254host: "localhost",255port: 8080,256timeout: 30 * time.Second,257maxConns: 100,258}259260// Apply options261for _, opt := range opts {262opt(s)263}264265return s266}267268// Usage:269// server := NewServer(270// WithHost("0.0.0.0"),271// WithPort(9000),272// WithTimeout(60 * time.Second),273// WithLogger(true),274// )275```276277## Interface Segregation278279```go280// Bad: Fat interface281type BadRepository interface {282Create(item Item) error283Read(id string) (Item, error)284Update(item Item) error285Delete(id string) error286List() ([]Item, error)287Search(query string) ([]Item, error)288Count() (int, error)289}290291// Good: Segregated interfaces292type Creator interface {293Create(item Item) error294}295296type Reader interface {297Read(id string) (Item, error)298}299300type Updater interface {301Update(item Item) error302}303304type Deleter interface {305Delete(id string) error306}307308type Lister interface {309List() ([]Item, error)310}311312// Compose only what you need313type ReadWriter interface {314Reader315Creator316}317318type FullRepository interface {319Creator320Reader321Updater322Deleter323Lister324}325```326327## Type Assertions and Type Switches328329```go330import "fmt"331332// Safe type assertion333func processValue(v interface{}) {334// Two-value assertion (safe)335if str, ok := v.(string); ok {336fmt.Println("String:", str)337return338}339340// Type switch341switch val := v.(type) {342case int:343fmt.Println("Int:", val)344case string:345fmt.Println("String:", val)346case bool:347fmt.Println("Bool:", val)348default:349fmt.Println("Unknown type")350}351}352353// Check for optional interface methods354type Flusher interface {355Flush() error356}357358func writeAndFlush(w io.Writer, data []byte) error {359if _, err := w.Write(data); err != nil {360return err361}362363// Check if Writer also implements Flusher364if flusher, ok := w.(Flusher); ok {365return flusher.Flush()366}367368return nil369}370```371372## Dependency Injection via Interfaces373374```go375package app376377import "context"378379// Define interfaces for dependencies380type UserRepository interface {381GetUser(ctx context.Context, id string) (*User, error)382SaveUser(ctx context.Context, user *User) error383}384385type EmailSender interface {386SendEmail(ctx context.Context, to, subject, body string) error387}388389// Service depends on interfaces390type UserService struct {391repo UserRepository392mailer EmailSender393}394395func NewUserService(repo UserRepository, mailer EmailSender) *UserService {396return &UserService{397repo: repo,398mailer: mailer,399}400}401402func (s *UserService) RegisterUser(ctx context.Context, email string) error {403user := &User{Email: email}404if err := s.repo.SaveUser(ctx, user); err != nil {405return err406}407return s.mailer.SendEmail(ctx, email, "Welcome", "Thanks for registering!")408}409410// Easy to mock in tests411type MockUserRepository struct{}412413func (m *MockUserRepository) GetUser(ctx context.Context, id string) (*User, error) {414return &User{ID: id}, nil415}416417func (m *MockUserRepository) SaveUser(ctx context.Context, user *User) error {418return nil419}420```421422## Quick Reference423424| Pattern | Use Case | Key Principle |425|---------|----------|---------------|426| Small interfaces | Flexibility | Single-method interfaces |427| Accept interfaces | Testability | Depend on abstractions |428| Return structs | Clarity | Concrete return types |429| io.Reader/Writer | I/O operations | Standard library integration |430| Embedding | Composition | Extend behavior without inheritance |431| Functional options | Configuration | Flexible constructors |432| Type assertions | Runtime checks | Safe downcasting |433