Source profileQuality 67/100Review permissions

affaan-m/ECC/docs/zh-CN/skills/golang-patterns/SKILL.md

golang-patterns

Review golang-patterns's use cases, installation, workflow, and original source instructions.

Source repository stars
234,327
Declared platforms
0
Static risk flags
3
Last source update
2026-07-27
Source checked
2026-07-28

Decision brief

What it does—and where it fits

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

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/affaan-m/ECC --skill "docs/zh-CN/skills/golang-patterns"
    Safe inspection promptEditorial

    Inspect the Agent Skill "golang-patterns" from https://github.com/affaan-m/ECC/blob/4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38/docs/zh-CN/skills/golang-patterns/SKILL.md at commit 4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      何时激活

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

      编写新的 Go 代码时审查 Go 代码时重构现有 Go 代码时
    2. 02

      核心原则

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

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

      1. 简洁与清晰

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

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

      2. 让零值变得有用

      Review the “2. 让零值变得有用” section in the pinned source before continuing.

      Review and apply the “2. 让零值变得有用” source section.
    5. 05

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

      Review the “3. 接受接口,返回结构体” section in the pinned source before continuing.

      Review and apply the “3. 接受接口,返回结构体” source section.

    Permission review

    Static risk signals and limitations

    Reads files

    low · line 94

    The documentation asks the agent to read local files, directories, or repositories.

    data, err := os.ReadFile(path)

    Network access

    medium · line 205

    The documentation includes network, browsing, or remote request actions.

    return nil, fmt.Errorf("fetch %s: %w", url, err)

    Network access

    medium · line 269

    The documentation includes network, browsing, or remote request actions.

    data, _ := fetch(url)

    Runs scripts

    medium · line 570

    The documentation asks the agent to run terminal commands or scripts.

    go build ./...

    Runs scripts

    medium · line 571

    The documentation asks the agent to run terminal commands or scripts.

    go run ./cmd/myapp

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score67/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars234,327SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    affaan-m/ECC
    Skill path
    docs/zh-CN/skills/golang-patterns/SKILL.md
    Commit
    4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38
    License
    MIT
    Collected
    2026-07-28
    Default branch
    main
    View the original 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:
        enable:
          - shadow
    
    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 代码应该以最好的方式显得“乏味”——可预测、一致且易于理解。如有疑问,保持简单。

    Alternatives

    Compare before choosing