go-code-review
Use when reviewing Go code or checking code against community style standards. Also use proactively before submitting a Go PR or…
Use when writing conditionals, loops, or switch statements in Go — including if with initialization, early returns, for loop forms, range, switch, type switches, and blank identifier patterns. Also use when writing a simple if/else or for loop, even if the user doesn't mention
$ npx -y skills add cxuu/golang-skills --skill go-control-flow --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/go-control-flowContext preview
The summary Claude sees to decide when to auto-load this skill.
Use when writing conditionals, loops, or switch statements in Go — including if with initialization, early returns, for loop forms, range, switch, type switches, and blank identifier patterns. Also use when writing a simple if/else or for loop, even if the user doesn't mention
name: go-control-flow description: Use when writing conditionals, loops, or switch statements in Go — including if with initialization, early returns, for loop forms, range, switch, type switches, and blank identifier patterns. Also use when writing a simple if/else or for loop, even if the user doesn't mention guard clauses or variable scoping. Does not cover error flow patterns (see go-error-handling).
---
`if` and `switch` accept an optional initialization statement. Use it to scope variables to the conditional block:
if err := file.Chmod(0664); err != nil {
log.Print(err)
return err
}If you need the variable beyond a few lines after the `if`, declare it separately and use a standard `if` instead:
x, err := f()
if err != nil {
return err
}
// lots of code that uses xWhen an `if` body ends with `break`, `continue`, `goto`, or `return`, omit the unnecessary `else`. Keep the success path unindented:
f, err := os.Open(name)
if err != nil {
return err
}
d, err := f.Stat()
if err != nil {
f.Close()
return err
}
codeUsing(f, d)Never bury normal flow inside an `else` when the `if` already returns.
---
The `:=` short declaration allows redeclaring variables in the same scope:
f, err := os.Open(name) // declares f and err d, err := f.Stat() // declares d, reassigns err
A variable `v` may appear in a `:=` declaration even if already declared, provided:
1. The declaration is in the **same scope** as the existing `v` 2. The value is **assignable** to `v` 3. At least **one other variable** is newly created by the declaration
**Warning**: If `v` is declared in an outer scope, `:=` creates a **new** variable that shadows it — a common source of bugs:
// Bug: ctx inside the if block shadows the outer ctx
if *shortenDeadlines {
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()
}
// ctx here is still the original — the shadowed ctx didn't escape
// Fix: use = instead of :=
var cancel func()
ctx, cancel = context.WithTimeout(ctx, 3*time.Second)---
Go's `for` is its only looping construct, unifying `while`, `do-while`, and C-style `for`:
// Condition-only (Go's "while")
for x > 0 {
x = process(x)
}
// Infinite loop
for {
if done() { break }
}
// C-style three-component
for i := 0; i < n; i++ { ... }`range` iterates over slices, maps, strings, and channels:
for i, v := range slice { ... } // index + value
for k, v := range myMap { ... } // key + value (non-deterministic order)
for i, r := range "héllo" { ... } // byte index + rune (not byte)
for v := range ch { ... } // receives until channel closed**Key rules:**
Go has no comma operator. Use parallel assignment for multiple loop variables:
for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
a[i], a[j] = a[j], a[i]
}`++` and `--` are statements, not expressions — they cannot appear in parallel assignment.
---
`break` inside a `switch` within a `for` loop only breaks the switch. Use a labeled `break` to exit the enclosing loop:
Loop:
for _, v := range items {
switch v.Type {
case "done":
break Loop // breaks the for loop
}
}For type switches, see **go-interfaces**: Type Switch.
---
**Never discard errors carelessly** — a nil dereference panic may follow.
Route compile-time interface assertions to [go-interfaces](../go-interfaces/SKILL.md).
---
| Pattern | Go Idiom | |---------|----------| | If initialization | `if err := f(); err != nil { }` | | Early return | Omit `else` when if body returns | | Redeclaration | `:=` reassigns if same scope + new var | | Shadowing trap | `:=` in inner scope creates new variable | | Parallel assignment | `i, j = i+1, j-1` | | Expression-less switch | `switch { case cond: }` | | Comma cases | `case 'a', 'b', 'c':` | | No fallthrough | Default behavior (explicit `fallthrough` if needed) | | Break from loop in switch | `break Label` | | Discard value | `_, err := f()` | | Side-effect import | `import _ "pkg"` | | Interface check | Route to go-interfaces |
---
AI Agent Skills for writing idiomatic, production-quality Go code. 20 modular skills teach AI coding assistants Go best practices derived from: Google Go Style Guide Effective Go Uber Go Style Guide Go Wiki CodeReviewComments Skills are tuned following
Use when reviewing Go code or checking code against community style standards. Also use proactively before submitting a Go PR or…
Use when writing concurrent Go code — goroutines, channels, mutexes, or thread-safety guarantees. Also use when parallelizing…
Use when working with context.Context in Go — placement in signatures, propagating cancellation and deadlines, and storing values…
Use when working with Go slices, maps, or arrays — choosing between new and make, using append, declaring empty slices (nil vs…
Use when declaring or initializing Go variables, constants, structs, or maps — including var vs :=, reducing scope with if-init,…
Use when hardening Go code at API boundaries — copying slices/maps, verifying interface compliance, using defer for cleanup,…