Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    affaan-m

    golang-patterns

    affaan-m/golang-patterns
    Coding
    42,727
    16 installs

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    构建稳健、高效且可维护的Go应用程序的惯用Go模式、最佳实践和约定。

    SKILL.md

    Go 开发模式

    用于构建健壮、高效和可维护应用程序的惯用 Go 模式与最佳实践。

    何时激活

    • 编写新的 Go 代码时
    • 审查 Go 代码时
    • 重构现有 Go 代码时
    • 设计 Go 包/模块时

    核心原则

    1. 简洁与清晰

    Go 推崇简洁而非精巧。代码应该显而易见且易于阅读。

    // Good: Clear and direct
    func GetUser(id string) (*User, error) {
        user, err := db.FindUser(id)
        if err != nil {
            return nil, fmt.Errorf("get user %s: %w", id, err)
        }
        return user, nil
    }
    
    // Bad: Overly clever
    func GetUser(id string) (*User, error) {
        return func() (*User, error) {
            if u, e := db.FindUser(id); e == nil {
                return u, nil
            } else {
                return nil, e
            }
        }()
    }
    

    2. 让零值变得有用

    设计类型时,应使其零值无需初始化即可立即使用。

    // Good: Zero value is useful
    type Counter struct {
        mu    sync.Mutex
        count int // zero value is 0, ready to use
    }
    
    func (c *Counter) Inc() {
        c.mu.Lock()
        c.count++
        c.mu.Unlock()
    }
    
    // Good: bytes.Buffer works with zero value
    var buf bytes.Buffer
    buf.WriteString("hello")
    
    // Bad: Requires initialization
    type BadCounter struct {
        counts map[string]int // nil map will panic
    }
    

    3. 接受接口,返回结构体

    函数应该接受接口参数并返回具体类型。

    // Good: Accepts interface, returns concrete type
    func ProcessData(r io.Reader) (*Result, error) {
        data, err := io.ReadAll(r)
        if err != nil {
            return nil, err
        }
        return &Result{Data: data}, nil
    }
    
    // Bad: Returns interface (hides implementation details unnecessarily)
    func ProcessData(r io.Reader) (io.Reader, error) {
        // ...
    }
    

    错误处理模式

    带上下文的错误包装

    // Good: Wrap errors with context
    func LoadConfig(path string) (*Config, error) {
        data, err := os.ReadFile(path)
        if err != nil {
            return nil, fmt.Errorf("load config %s: %w", path, err)
        }
    
        var cfg Config
        if err := json.Unmarshal(data, &cfg); err != nil {
            return nil, fmt.Errorf("parse config %s: %w", path, err)
        }
    
        return &cfg, nil
    }
    

    自定义错误类型

    // Define domain-specific errors
    type ValidationError struct {
        Field   string
        Message string
    }
    
    func (e *ValidationError) Error() string {
        return fmt.Sprintf("validation failed on %s: %s", e.Field, e.Message)
    }
    
    // Sentinel errors for common cases
    var (
        ErrNotFound     = errors.New("resource not found")
        ErrUnauthorized = errors.New("unauthorized")
        ErrInvalidInput = errors.New("invalid input")
    )
    

    使用 errors.Is 和 errors.As 检查错误

    func HandleError(err error) {
        // Check for specific error
        if errors.Is(err, sql.ErrNoRows) {
            log.Println("No records found")
            return
        }
    
        // Check for error type
        var validationErr *ValidationError
        if errors.As(err, &validationErr) {
            log.Printf("Validation error on field %s: %s",
                validationErr.Field, validationErr.Message)
            return
        }
    
        // Unknown error
        log.Printf("Unexpected error: %v", err)
    }
    

    永不忽略错误

    // Bad: Ignoring error with blank identifier
    result, _ := doSomething()
    
    // Good: Handle or explicitly document why it's safe to ignore
    result, err := doSomething()
    if err != nil {
        return err
    }
    
    // Acceptable: When error truly doesn't matter (rare)
    _ = writer.Close() // Best-effort cleanup, error logged elsewhere
    

    并发模式

    工作池

    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)
    }
    

    用于取消和超时的 Context

    func FetchWithTimeout(ctx context.Context, url string) ([]byte, error) {
        ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
        defer cancel()
    
        req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
        if err != nil {
            return nil, fmt.Errorf("create request: %w", err)
        }
    
        resp, err := http.DefaultClient.Do(req)
        if err != nil {
            return nil, fmt.Errorf("fetch %s: %w", url, err)
        }
        defer resp.Body.Close()
    
        return io.ReadAll(resp.Body)
    }
    

    优雅关闭

    func GracefulShutdown(server *http.Server) {
        quit := make(chan os.Signal, 1)
        signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
    
        <-quit
        log.Println("Shutting down server...")
    
        ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
        defer cancel()
    
        if err := server.Shutdown(ctx); err != nil {
            log.Fatalf("Server forced to shutdown: %v", err)
        }
    
        log.Println("Server exited")
    }
    

    用于协调 Goroutine 的 errgroup

    import "golang.org/x/sync/errgroup"
    
    func FetchAll(ctx context.Context, urls []string) ([][]byte, error) {
        g, ctx := errgroup.WithContext(ctx)
        results := make([][]byte, len(urls))
    
        for i, url := range urls {
            i, url := i, url // Capture loop variables
            g.Go(func() error {
                data, err := FetchWithTimeout(ctx, url)
                if err != nil {
                    return err
                }
                results[i] = data
                return nil
            })
        }
    
        if err := g.Wait(); err != nil {
            return nil, err
        }
        return results, nil
    }
    

    避免 Goroutine 泄漏

    // Bad: Goroutine leak if context is cancelled
    func leakyFetch(ctx context.Context, url string) <-chan []byte {
        ch := make(chan []byte)
        go func() {
            data, _ := fetch(url)
            ch <- data // Blocks forever if no receiver
        }()
        return ch
    }
    
    // Good: Properly handles cancellation
    func safeFetch(ctx context.Context, url string) <-chan []byte {
        ch := make(chan []byte, 1) // Buffered channel
        go func() {
            data, err := fetch(url)
            if err != nil {
                return
            }
            select {
            case ch <- data:
            case <-ctx.Done():
            }
        }()
        return ch
    }
    

    接口设计

    小而专注的接口

    // Good: Single-method interfaces
    type Reader interface {
        Read(p []byte) (n int, err error)
    }
    
    type Writer interface {
        Write(p []byte) (n int, err error)
    }
    
    type Closer interface {
        Close() error
    }
    
    // Compose interfaces as needed
    type ReadWriteCloser interface {
        Reader
        Writer
        Closer
    }
    

    在接口使用处定义接口

    // In the consumer package, not the provider
    package service
    
    // UserStore defines what this service needs
    type UserStore interface {
        GetUser(id string) (*User, error)
        SaveUser(user *User) error
    }
    
    type Service struct {
        store UserStore
    }
    
    // Concrete implementation can be in another package
    // It doesn't need to know about this interface
    

    使用类型断言实现可选行为

    type Flusher interface {
        Flush() error
    }
    
    func WriteAndFlush(w io.Writer, data []byte) error {
        if _, err := w.Write(data); err != nil {
            return err
        }
    
        // Flush if supported
        if f, ok := w.(Flusher); ok {
            return f.Flush()
        }
        return nil
    }
    

    包组织

    标准项目布局

    myproject/
    ├── cmd/
    │   └── myapp/
    │       └── main.go           # 入口点
    ├── internal/
    │   ├── handler/              # HTTP 处理器
    │   ├── service/              # 业务逻辑
    │   ├── repository/           # 数据访问
    │   └── config/               # 配置
    ├── pkg/
    │   └── client/               # 公共 API 客户端
    ├── api/
    │   └── v1/                   # API 定义(proto, OpenAPI)
    ├── testdata/                 # 测试夹具
    ├── go.mod
    ├── go.sum
    └── Makefile
    

    包命名

    // Good: Short, lowercase, no underscores
    package http
    package json
    package user
    
    // Bad: Verbose, mixed case, or redundant
    package httpHandler
    package json_parser
    package userService // Redundant 'Service' suffix
    

    避免包级状态

    // Bad: Global mutable state
    var db *sql.DB
    
    func init() {
        db, _ = sql.Open("postgres", os.Getenv("DATABASE_URL"))
    }
    
    // Good: Dependency injection
    type Server struct {
        db *sql.DB
    }
    
    func NewServer(db *sql.DB) *Server {
        return &Server{db: db}
    }
    

    结构体设计

    函数式选项模式

    type Server struct {
        addr    string
        timeout time.Duration
        logger  *log.Logger
    }
    
    type Option func(*Server)
    
    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(addr string, opts ...Option) *Server {
        s := &Server{
            addr:    addr,
            timeout: 30 * time.Second, // default
            logger:  log.Default(),    // default
        }
        for _, opt := range opts {
            opt(s)
        }
        return s
    }
    
    // Usage
    server := NewServer(":8080",
        WithTimeout(60*time.Second),
        WithLogger(customLogger),
    )
    

    使用嵌入实现组合

    type Logger struct {
        prefix string
    }
    
    func (l *Logger) Log(msg string) {
        fmt.Printf("[%s] %s\n", l.prefix, msg)
    }
    
    type Server struct {
        *Logger // Embedding - Server gets Log method
        addr    string
    }
    
    func NewServer(addr string) *Server {
        return &Server{
            Logger: &Logger{prefix: "SERVER"},
            addr:   addr,
        }
    }
    
    // Usage
    s := NewServer(":8080")
    s.Log("Starting...") // Calls embedded Logger.Log
    

    内存与性能

    当大小已知时预分配切片

    // Bad: Grows slice multiple times
    func processItems(items []Item) []Result {
        var results []Result
        for _, item := range items {
            results = append(results, process(item))
        }
        return results
    }
    
    // Good: Single allocation
    func processItems(items []Item) []Result {
        results := make([]Result, 0, len(items))
        for _, item := range items {
            results = append(results, process(item))
        }
        return results
    }
    

    为频繁分配使用 sync.Pool

    var bufferPool = sync.Pool{
        New: func() interface{} {
            return new(bytes.Buffer)
        },
    }
    
    func ProcessRequest(data []byte) []byte {
        buf := bufferPool.Get().(*bytes.Buffer)
        defer func() {
            buf.Reset()
            bufferPool.Put(buf)
        }()
    
        buf.Write(data)
        // Process...
        return buf.Bytes()
    }
    

    避免在循环中进行字符串拼接

    // Bad: Creates many string allocations
    func join(parts []string) string {
        var result string
        for _, p := range parts {
            result += p + ","
        }
        return result
    }
    
    // Good: Single allocation with strings.Builder
    func join(parts []string) string {
        var sb strings.Builder
        for i, p := range parts {
            if i > 0 {
                sb.WriteString(",")
            }
            sb.WriteString(p)
        }
        return sb.String()
    }
    
    // Best: Use standard library
    func join(parts []string) string {
        return strings.Join(parts, ",")
    }
    

    Go 工具集成

    基本命令

    # Build and run
    go build ./...
    go run ./cmd/myapp
    
    # Testing
    go test ./...
    go test -race ./...
    go test -cover ./...
    
    # Static analysis
    go vet ./...
    staticcheck ./...
    golangci-lint run
    
    # Module management
    go mod tidy
    go mod verify
    
    # Formatting
    gofmt -w .
    goimports -w .
    

    推荐的 Linter 配置 (.golangci.yml)

    linters:
      enable:
        - errcheck
        - gosimple
        - govet
        - ineffassign
        - staticcheck
        - unused
        - gofmt
        - goimports
        - misspell
        - unconvert
        - unparam
    
    linters-settings:
      errcheck:
        check-type-assertions: true
      govet:
        check-shadowing: true
    
    issues:
      exclude-use-default: false
    

    快速参考:Go 惯用法

    惯用法 描述
    接受接口,返回结构体 函数接受接口参数,返回具体类型
    错误即值 将错误视为一等值,而非异常
    不要通过共享内存来通信 使用通道在 goroutine 之间进行协调
    让零值变得有用 类型应无需显式初始化即可工作
    少量复制优于少量依赖 避免不必要的外部依赖
    清晰优于精巧 优先考虑可读性而非精巧性
    gofmt 虽非最爱,但却是每个人的朋友 始终使用 gofmt/goimports 格式化代码
    提前返回 先处理错误,保持主逻辑路径无缩进

    应避免的反模式

    // Bad: Naked returns in long functions
    func process() (result int, err error) {
        // ... 50 lines ...
        return // What is being returned?
    }
    
    // Bad: Using panic for control flow
    func GetUser(id string) *User {
        user, err := db.Find(id)
        if err != nil {
            panic(err) // Don't do this
        }
        return user
    }
    
    // Bad: Passing context in struct
    type Request struct {
        ctx context.Context // Context should be first param
        ID  string
    }
    
    // Good: Context as first parameter
    func ProcessRequest(ctx context.Context, id string) error {
        // ...
    }
    
    // Bad: Mixing value and pointer receivers
    type Counter struct{ n int }
    func (c Counter) Value() int { return c.n }    // Value receiver
    func (c *Counter) Increment() { c.n++ }        // Pointer receiver
    // Pick one style and be consistent
    

    记住:Go 代码应该以最好的方式显得“乏味”——可预测、一致且易于理解。如有疑问,保持简单。

    Recommended Servers
    Vercel Grep
    Vercel Grep
    Nimble MCP Server
    Nimble MCP Server
    Prisma
    Prisma
    Repository
    affaan-m/everything-claude-code
    Files