---
id: daily-golang-code-style
name: "golang-code-style"
url: https://skills.yangsir.net/skill/daily-golang-code-style
author: samber
domain: ai-code-generation-quality
tags: ["golang", "code-style", "code-review", "best-practices", "backend-development"]
install_count: 33900
rating: 4.60 (20 reviews)
github: https://github.com/samber/cc-skills-golang
---

# golang-code-style

> Go代码风格规范，关注需要人工判断的清晰度规则，与linter配合保障代码质量

**Stats**: 33,900 installs · 4.6/5 (20 reviews)

## Before / After 对比

### 代码一致性

**Before**:

团队开发Go代码时，命名、注释、结构组织风格不一，代码审查时反复讨论风格问题，影响开发效率

**After**:

提供统一的Go代码风格规范，自动检查命名和清晰度问题，与linter互补，减少代码审查中的风格争议

| Metric | Before | After | Change |
|---|---|---|---|
| 代码审查时间 | 30分钟/PR | 10分钟/PR | -67% |

## Readme

# golang-code-style

**Community default.** A company skill that explicitly supersedes `samber/cc-skills-golang@golang-code-style` skill takes precedence.

# Go Code Style

Style rules that require human judgment — linters handle formatting, this skill handles clarity. For naming see `samber/cc-skills-golang@golang-naming` skill; for design patterns see `samber/cc-skills-golang@golang-design-patterns` skill; for struct/interface design see `samber/cc-skills-golang@golang-structs-interfaces` skill.

"Clear is better than clever." — Go Proverbs

When ignoring a rule, add a comment to the code.

## Line Length & Breaking

No rigid line limit, but lines beyond ~120 characters MUST be broken. Break at **semantic boundaries**, not arbitrary column counts. Function calls with 4+ arguments MUST use one argument per line — even when the prompt asks for single-line code:

```
// Good — each argument on its own line, closing paren separate
mux.HandleFunc("/api/users", func(w http.ResponseWriter, r *http.Request) {
    handleUsers(
        w,
        r,
        serviceName,
        cfg,
        logger,
        authMiddleware,
    )
})

```

When a function signature is too long, the real fix is often **fewer parameters** (use an options struct) rather than better line wrapping. For multi-line signatures, put each parameter on its own line.

## Variable Declarations

SHOULD use `:=` for non-zero values, `var` for zero-value initialization. The form signals intent: `var` means "this starts at zero."

```
var count int              // zero value, set later
name := "default"          // non-zero, := is appropriate
var buf bytes.Buffer       // zero value is ready to use

```

### Slice & Map Initialization

Slices and maps MUST be initialized explicitly, never nil. Nil maps panic on write; nil slices serialize to `null` in JSON (vs `[]` for empty slices), surprising API consumers.

```
users := []User{}                       // always initialized
m := map[string]int{}                   // always initialized
users := make([]User, 0, len(ids))      // preallocate when capacity is known
m := make(map[string]int, len(items))   // preallocate when size is known

```

Do not preallocate speculatively — `make([]T, 0, 1000)` wastes memory when the common case is 10 items.

### Composite Literals

Composite literals MUST use field names — positional fields break when the type adds or reorders fields:

```
srv := &http.Server{
    Addr:         ":8080",
    ReadTimeout:  5 * time.Second,
    WriteTimeout: 10 * time.Second,
}

```

## Control Flow

### Reduce Nesting

Errors and edge cases MUST be handled first (early return). Keep the happy path at minimal indentation:

```
func process(data []byte) (*Result, error) {
    if len(data) == 0 {
        return nil, errors.New("empty data")
    }

    parsed, err := parse(data)
    if err != nil {
        return nil, fmt.Errorf("parsing: %w", err)
    }

    return transform(parsed), nil
}

```

### Eliminate Unnecessary `else`

When the `if` body ends with `return`/`break`/`continue`, the `else` MUST be dropped. Use default-then-override for simple assignments — assign a default, then override with independent conditions or a `switch`:

```
// Good — default-then-override with switch (cleanest for mutually exclusive overrides)
level := slog.LevelInfo
switch {
case debug:
    level = slog.LevelDebug
case verbose:
    level = slog.LevelWarn
}

// Bad — else-if chain hides that there's a default
if debug {
    level = slog.LevelDebug
} else if verbose {
    level = slog.LevelWarn
} else {
    level = slog.LevelInfo
}

```

### Complex Conditions & Init Scope

When an `if` condition has 3+ operands, MUST extract into named booleans — a wall of `||` is unreadable and hides business logic. Keep expensive checks inline for short-circuit benefit. [Details](https://github.com/samber/cc-skills-golang/blob/HEAD/skills/golang-code-style/./references/details.md)

```
// Good — named booleans make intent clear
isAdmin := user.Role == RoleAdmin
isOwner := resource.OwnerID == user.ID
isPublicVerified := resource.IsPublic && user.IsVerified
if isAdmin || isOwner || isPublicVerified || permissions.Contains(PermOverride) {
    allow()
}

```

Scope variables to `if` blocks when only needed for the check:

```
if err := validate(input); err != nil {
    return err
}

```

### Switch Over If-Else Chains

When comparing the same variable multiple times, prefer `switch`:

```
switch status {
case StatusActive:
    activate()
case StatusInactive:
    deactivate()
default:
    panic(fmt.Sprintf("unexpected status: %d", status))
}

```

## Function Design

- Functions SHOULD be **short and focused** — one function, one job.

- Functions SHOULD have **≤4 parameters**. Beyond that, use an options struct (see `samber/cc-skills-golang@golang-design-patterns` skill).

- **Parameter order**: `context.Context` first, then inputs, then output destinations.

- Naked returns help in very short functions (1-3 lines) where return values are obvious, but become confusing when readers must scroll to find what's returned — name returns explicitly in longer functions.

```
func FetchUser(ctx context.Context, id string) (*User, error)
func SendEmail(ctx context.Context, msg EmailMessage) error  // grouped into struct

```

### Prefer `range` for Iteration

SHOULD use `range` over index-based loops. Use `range n` (Go 1.22+) for simple counting.

```
for _, user := range users {
    process(user)
}

```

## Value vs Pointer Arguments

Pass small types (`string`, `int`, `bool`, `time.Time`) by value. Use pointers when mutating, for large structs (~128+ bytes), or when nil is meaningful. [Details](https://github.com/samber/cc-skills-golang/blob/HEAD/skills/golang-code-style/./references/details.md)

## Code Organization Within Files

- **Group related declarations**: type, constructor, methods together

- **Order**: package doc, imports, constants, types, constructors, methods, helpers

- **One primary type per file** when it has significant methods

- **Blank imports** (`_ "pkg"`) register side effects (init functions). Restricting them to `main` and test packages makes side effects visible at the application root, not hidden in library code

- **Dot imports** pollute the namespace and make it impossible to tell where a name comes from — never use in library code

- **Unexport aggressively** — you can always export later; unexporting is a breaking change

## String Handling

Use `strconv` for simple conversions (faster), `fmt.Sprintf` for complex formatting. Use `%q` in error messages to make string boundaries visible. Use `strings.Builder` for loops, `+` for simple concatenation.

## Type Conversions

Prefer explicit, narrow conversions. Use generics over `any` when a concrete type will do:

```
func Contains[T comparable](slice []T, target T) bool  // not []any

```

## Philosophy

- **"A little copying is better than a little dependency"**

- **Use `slices` and `maps` standard packages**; for filter/group-by/chunk, use `github.com/samber/lo`

- **"Reflection is never clear"** — avoid `reflect` unless necessary

- **Don't abstract prematurely** — extract when the pattern is stable

- **Minimize public surface** — every exported name is a commitment

## Parallelizing Code Style Reviews

When reviewing code style across a large codebase, use up to 5 parallel sub-agents (via the Agent tool), each targeting an independent style concern (e.g. control flow, function design, variable declarations, string handling, code organization).

## Enforce with Linters

Many rules are enforced automatically: `gofmt`, `gofumpt`, `goimports`, `gocritic`, `revive`, `wsl_v5`. → See the `samber/cc-skills-golang@golang-linter` skill.

## Cross-References

- → See the `samber/cc-skills-golang@golang-naming` skill for identifier naming conventions

- → See the `samber/cc-skills-golang@golang-structs-interfaces` skill for pointer vs value receivers, interface design

- → See the `samber/cc-skills-golang@golang-design-patterns` skill for functional options, builders, constructors

- → See the `samber/cc-skills-golang@golang-linter` skill for automated formatting enforcement

Weekly Installs801Repository[samber/cc-skills-golang](https://github.com/samber/cc-skills-golang)GitHub Stars1.1KFirst SeenMar 22, 2026Security Audits[Gen Agent Trust HubPass](/samber/cc-skills-golang/golang-code-style/security/agent-trust-hub)[SocketPass](/samber/cc-skills-golang/golang-code-style/security/socket)[SnykPass](/samber/cc-skills-golang/golang-code-style/security/snyk)Installed onopencode760cursor754codex749gemini-cli747github-copilot746amp745

---
*Source: https://skills.yangsir.net/skill/daily-golang-code-style*
*Markdown mirror: https://skills.yangsir.net/api/skill/daily-golang-code-style/markdown*