Skip to content
Development
Skill

/go-control-flow

Use when writing conditionals, loops, switches, type switches, or blank-identifier patterns in Go. Covers if-with-initialization, guard clauses, early returns, the unified for loop, range over slices/maps/strings/channels, parallel assignment, labeled break, and `_` for discards

From plugin
gophers
926 skills4 agents

Claude Code

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

SKILL.md

go-control-flow.SKILL.md
name: go-control-flow
description: "Use when writing conditionals, loops, switches, type switches, or blank-identifier patterns in Go. Covers if-with-initialization, guard clauses, early returns, the unified for loop, range over slices/maps/strings/channels, parallel assignment, labeled break, and `_` for discards and side-effect imports. Apply proactively to any new if/for/switch, even when the user does not mention scoping or shadowing. Does not cover error-flow specifics (see go-error-handling)."
license: MIT
compatibility: "Designed for Claude Code or similar AI coding agents. Plain Go (any supported version)."
allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(golangci-lint:*)

Go Control Flow

Go gives you `if`, `for`, and `switch` — and one looping construct that covers them all. The idioms are small but strict: scope variables tightly, return early, keep the happy path unindented.

Core Rules

1. **Scope variables with if-init when they live only for the check.** `if x, err := f(); err != nil { ... }`. 2. **Guard clauses over nested `else`.** When the `if` body returns/breaks/continues, drop the `else`. 3. **`:=` redeclares only in the same scope.** In an inner scope it shadows — a frequent bug source. 4. **One `for`, three forms.** Condition-only (while), three-clause (C-style), and infinite (`for {}`). 5. **`range` over string yields runes**, over map yields **non-deterministic order**, over channel **drains until closed**. 6. **`break` inside `switch` only breaks the switch.** Use a labeled `break` to exit the enclosing `for`. 7. **The blank identifier `_` discards, but never errors.** Silent error dropping is a bug.

Decision: var vs := vs = at a glance

| Situation | Use | |---|---| | New variable, scoped to the check | `if v, err := f(); err != nil` | | Reusing an outer variable | plain `=` (avoid `:=` to prevent shadowing) | | At least one new + reuse of outer | `:=` is fine (same scope only) | | Wanted zero value | `var x T` |

If with Initialization

if err := file.Chmod(0664); err != nil {
    return err
}

If `err` is needed past the `if`, declare it separately:

x, err := f()
if err != nil {
    return err
}
// use x freely

Guard Clauses

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 the success path inside `else`.

The Shadowing Trap

// Bug: inner ctx never escapes the if block
if *shortenDeadlines {
    ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
    defer cancel()
}

// Fix: assign with =, declaring cancel separately
var cancel func()
ctx, cancel = context.WithTimeout(ctx, 3*time.Second)
defer cancel()

> Read [references/blank-identifier.md](references/blank-identifier.md) for `_` use cases (interface checks, side-effect imports, multi-return discards).

For Loops

// Condition-only (Go's "while")
for x > 0 { x = process(x) }

// Infinite
for {
    if done() { break }
}

// Three-clause
for i := 0; i < n; i++ { ... }

Range

for i, v := range slice { ... }   // index + value
for k, v := range myMap  { ... }  // non-deterministic order
for i, r := range "héllo" { ... } // i is byte offset; r is rune
for v := range ch { ... }         // drains until closed

Parallel Assignment

Go has no comma operator. Use parallel assignment instead:

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 inside a parallel assignment.

Switch and Labeled Break

Loop:
    for _, v := range items {
        switch v.Type {
        case "done":
            break Loop // breaks the for, not just the switch
        }
    }

> Read [references/switch-patterns.md](references/switch-patterns.md) for expression-less switches, comma cases, fallthrough, and type switches.

Anti-Patterns

| Anti-pattern | Why it hurts | Do this instead | |---|---|---| | `} else { return ... }` after a returning `if` | Pointless nesting | Drop `else`; let the happy path stay flat | | `if _, err := f(); err == nil { ... }` then use the value | Value is out of scope | Move the `:=` outside the `if` | | `:=` in inner scope reassigning outer var | Silently shadows | Use `=` (declare the new locals separately) | | Iterating a map and relying on order | Order is randomized | Sort keys explicitly | | `break` inside `switch` expecting to exit `for` | Only exits switch | Use labeled `break Label` | | `_ = doSomething()` to silence an error | Real failures vanish | Handle it or document why |

Verification Checklist

  • [ ] No `else` branch after an `if` that returns/breaks/continues
  • [ ] `:=` in inner scopes does not shadow important outer variables
  • [ ] Loops use the simplest of the three forms that fits
  • [ ] `range` over strings treats the index as a byte offset, not a rune index
  • [ ] Map iteration does not assume an order
  • [ ] Errors are never silently discarded with `_`
  • [ ] Labeled `break` is used when a switch needs to exit a surrounding loop

References

  • [references/switch-patterns.md](references/switch-patterns.md) — expression-less, comma cases, fallthrough, type switches
  • [references/blank-identifier.md](references/blank-identifier.md) — `_` for multi-return, interface compliance, side-effect imports
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-data-structures

go-data-structures

Use when choosing or operating on Go slices, maps, arrays, strings, or container/* types — including slice internals, capacity…

@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-control-flow.

Which coding agents can use go-control-flow?
go-control-flow 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.