Skip to content
Development
Skill

/go-declarations

Use when declaring or initializing Go variables, constants, structs, or maps. Covers var vs :=, grouped declaration blocks, iota enums starting at 1, struct/map/slice composite literals, raw string literals, `any` over `interface{}`, and avoiding shadowed builtins. Apply

From plugin
gophers
926 skills4 agents

Claude Code

$ npx -y skills add muratmirgun/gophers --skill go-declarations --agent claude-code

SKILL.md

go-declarations.SKILL.md
name: go-declarations
description: "Use when declaring or initializing Go variables, constants, structs, or maps. Covers var vs :=, grouped declaration blocks, iota enums starting at 1, struct/map/slice composite literals, raw string literals, `any` over `interface{}`, and avoiding shadowed builtins. Apply proactively to any new struct, const block, or top-level var, even if the user did not ask about declaration style. Does not cover identifier naming (see go-naming)."
license: MIT
compatibility: "Designed for Claude Code or similar AI coding agents. `any` requires Go 1.18+."
allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*)

Go Declarations and Initialization

Pick the simplest declaration form that expresses your intent: scope variables tightly, group related declarations, and let the zero value do its job.

Core Rules

1. **`:=` for locals with values; `var` for intentional zero values or top-level declarations.** 2. **Group related declarations in parenthesized blocks.** Separate unrelated ones into distinct blocks. 3. **Start enums at `iota + 1`** so the zero value is "invalid/unset" — unless zero is genuinely meaningful. 4. **Initialize structs with field names.** Omit zero-value fields; let defaults speak. 5. **Use `any`, not `interface{}`,** in all new code. 6. **Never shadow builtins** (`len`, `cap`, `error`, `new`, `make`, `copy`, `any`, `nil`, ...).

Decision: var vs :=

| Context | Use | Example | |---|---|---| | Package-level | `var` (always) | `var startTime = time.Now()` | | Local with computed value | `:=` | `s := "foo"` | | Local zero-value, intentional | `var` | `var filtered []int` | | Declared type differs from RHS | `var T = expr` | `var e error = f()` |

> Read [references/scope-and-shadowing.md](references/scope-and-shadowing.md) when fighting subtle bugs caused by `:=` redeclaring an outer variable.

Group Related Declarations

// Bad
const a = 1
const b = 2

// Good
const (
    a = 1
    b = 2
)

Inside functions, group adjacent vars even if loosely related:

var (
    caller  = c.name
    format  = "json"
    timeout = 5 * time.Second
)

Constants and iota

Zero is the default; reserve it for "uninitialized" by starting enums at `iota + 1`:

type Operation int

const (
    Add      Operation = iota + 1 // 1
    Subtract                      // 2
    Multiply                      // 3
)

Use plain `iota` only when the zero value is the sensible default (e.g., `LogToStdout = iota`).

> Read [references/iota-and-literals.md](references/iota-and-literals.md) for bitmask enums, `String()` methods, raw strings, and composite-literal formatting.

Initializing Structs

  • **Always use field names.** Positional struct literals break on field reordering and are caught by `go vet`.
  • **Omit zero-value fields** — clarity beats explicit zeros.
  • **`var u User`** for a zero-value struct (not `u := User{}`).
  • **`&T{...}` over `new(T)`** when you want a pointer.
u := User{Name: "Ada", Email: "ada@example.com"}
sptr := &Config{Timeout: 5 * time.Second}
var empty Buffer // zero value, ready to use

Test tables with ≤3 fields may use positional literals when the meaning is obvious.

Initializing Maps

| Scenario | Use | Example | |---|---|---| | Empty, will be populated | `make(map[K]V)` | `m := make(map[string]int)` | | Nil, lazily allocated | `var` | `var m map[string]int` | | Known entries up front | Literal | `m := map[string]int{"a": 1}` |

`make` signals "initialized but empty" — different from a nil map (which panics on write). Provide a size hint when the count is known: `make(map[K]V, n)`.

Raw String Literals

Use backticks to avoid escape gymnastics:

// Bad
re := "^\\s*name:\\s*\"(.*)\""

// Good
re := `^\s*name:\s*"(.*)"`

Ideal for regex, SQL, JSON, and multi-line text.

`any`, not `interface{}`

// Old
func Print(v interface{}) { ... }

// New
func Print(v any) { ... }

`any` is an alias for `interface{}` since Go 1.18 — same type, less noise.

Don't Shadow Builtins

The predeclared identifiers (`error`, `string`, `len`, `cap`, `append`, `copy`, `new`, `make`, `close`, `delete`, `panic`, `recover`, `any`, `true`, `false`, `nil`, `iota`) are not reserved words — Go lets you shadow them. Don't.

// Bad — shadows the builtin error type
var error string

// Good
var errorMessage string

`go vet` catches the most common cases.

> Read [references/structs-and-tags.md](references/structs-and-tags.md) when designing struct fields that cross a serialization boundary (JSON, YAML, protobuf), embedding types, or formatting many-field literals.

Anti-Patterns

| Anti-pattern | Why it hurts | Do this instead | |---|---|---| | `u := User{}` for a zero value | Misleads readers into expecting non-defaults | `var u User` | | `new(T)` then assign fields | Two-step where one works | `&T{Field: v}` | | Positional struct literals (>3 fields) | Silent breakage on field reordering | Use field names | | `iota` starting at 0 for an enum | Zero value collides with a real case | `iota + 1` | | `var m map[string]int` then `m[k] = v` | Panic on nil map write | `m := make(map[string]int)` | | Hand-escaped JSON or regex strings | Hard to read, easy to mistype | Raw string literal | | `interface{}` in new code | Verbose, outdated | `any` |

Verification Checklist

  • [ ] Top-level declarations use `var`/`const`; locals use `:=` unless zero-value is intended
  • [ ] Related `const`/`var`/`type` are in grouped blocks
  • [ ] Enums start at `iota + 1` (or the zero value is explicitly meaningful)
  • [ ] Struct literals use field names; zero-value fields are omitted
  • [ ] Maps that will be written to are constructed with `make`
  • [ ] No builtins shadowed (`error`, `len`, `cap`, ...)
  • [ ] `any` used instead of `interface{}`

References

  • [references/scope-and-shadowing.md](references/scope-and-shadowing.md) — variable scope, `:=` redeclaration rules, shadowing traps

-

Read more
@muratmirgun
Ships withgophers

26 production-grade Go skills for Claude Code, Gemini CLI, and opencode. Battle-tested patterns from the Go community — codified as triggerable AI skills.

926 skills4 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
9
Star history of muratmirgun/gophers on GitHub, a chart by star-history.com

Other skills on gophers.

go-clean-architecture

go-clean-architecture

Use when scaffolding or refactoring a Go service into a framework-agnostic clean (hexagonal) architecture: Domain, Usecase,…

@muratmirgun@muratmirgunInstall Skill
go-code-review

go-code-review

Invoke this skill to systematically review a Go change against community style standards before merging. Walks the diff topic by…

@muratmirgun@muratmirgunInstall Skill
go-code-style

go-code-style

Use when writing or reviewing Go code for clarity, formatting, control flow, variable declarations, switch usage, and function…

@muratmirgun@muratmirgunInstall Skill
go-concurrency

go-concurrency

Use when writing or reviewing concurrent Go code — goroutines, channels, select, mutexes, atomics, errgroup, singleflight, worker…

@muratmirgun@muratmirgunInstall Skill
go-context

go-context

Use when designing, propagating, or debugging context.Context flow in Go — first-parameter placement, deadlines and cancellation,…

@muratmirgun@muratmirgunInstall Skill
go-control-flow

go-control-flow

Use when writing conditionals, loops, switches, type switches, or blank-identifier patterns in Go. Covers if-with-initialization,…

@muratmirgun@muratmirgunInstall Skill

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills2w309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react5d252k
@facebook@facebookInstall Skill

Questions about go-declarations.

Which coding agents can use go-declarations?
go-declarations installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.