PluginBench
Skill
Pass
Audit score 90

go-control-flow

cxuu/golang-skills

How to install go-control-flow

npx skills add https://github.com/cxuu/golang-skills --skill go-control-flow
Claude Code
Cursor
Windsurf
Cline
Full instructions (SKILL.md)

Source of truth, from cxuu/golang-skills.


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).

Go Control Flow

Resource Routing

  • references/SWITCH-PATTERNS.md - Read when using switch statements, type switches, fallthrough, or labeled breaks.
  • references/BLANK-IDENTIFIER.md - Read when using _, blank imports, unused compile-time assertions, or intentional discards.

If with Initialization

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 x

Indent Error Flow (Guard Clauses)

When 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.


Redeclaration and Reassignment

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

Variable Shadowing

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)

For Loops

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

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:

  • Range over strings yields runes, not bytes — i is the byte offset
  • Range over maps has non-deterministic order — don't rely on it
  • Use _ to discard the index or value: for _, v := range slice

Parallel Assignment

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.


Switch: Labeled Break

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.


The Blank Identifier

Never discard errors carelessly — a nil dereference panic may follow.

Route compile-time interface assertions to go-interfaces.


Quick Reference

PatternGo Idiom
If initializationif err := f(); err != nil { }
Early returnOmit else when if body returns
Redeclaration:= reassigns if same scope + new var
Shadowing trap:= in inner scope creates new variable
Parallel assignmenti, j = i+1, j-1
Expression-less switchswitch { case cond: }
Comma casescase 'a', 'b', 'c':
No fallthroughDefault behavior (explicit fallthrough if needed)
Break from loop in switchbreak Label
Discard value_, err := f()
Side-effect importimport _ "pkg"
Interface checkRoute to go-interfaces

Related Skills

  • Error flow: See go-error-handling when structuring guard clauses, early returns, or error-first patterns
  • Type switches: See go-interfaces when using type switches, the comma-ok idiom, or interface satisfaction checks
  • Nesting reduction: See go-style-core when reducing nesting depth or resolving formatting questions
  • Variable scoping: See go-declarations when using if-init, := redeclaration, or reducing variable scope

Related skills

More from cxuu/golang-skills and the wider catalog.

GOgo-data-structures logo

go-data-structures

cxuu/golang-skills

Use when working with Go slices, maps, or arrays — choosing between new and make, using append, declaring empty slices (nil vs literal for JSON), implementing sets with maps, and copying data at boundaries. Also use when building or manipulating collections, even if the user doesn't ask about allocation idioms. Does not cover concurrent data structure safety (see go-concurrency).

731 installsAudited
GOgo-defensive logo

go-defensive

cxuu/golang-skills

Use when hardening Go code at API boundaries — copying slices/maps, verifying interface compliance, using defer for cleanup, time.Time/time.Duration, or avoiding mutable globals. Also use when reviewing for robustness concerns like missing cleanup or unsafe crypto usage, even if the user doesn't mention "defensive programming." Does not cover error handling strategy (see go-error-handling).

737 installsAudited
GOgo-documentation logo

go-documentation

cxuu/golang-skills

Use when writing or reviewing documentation for Go packages, types, functions, or methods. Also use proactively when creating new exported types, functions, or packages, even if the user doesn't explicitly ask about documentation. Does not cover code comments for non-exported symbols (see go-style-core).

783 installsAudited
GOgo-error-handling logo

go-error-handling

cxuu/golang-skills

Use when writing Go code that returns, wraps, or handles errors — choosing between sentinel errors, custom types, and fmt.Errorf (%w vs %v), structuring error flow, or deciding whether to log or return. Also use when propagating errors across package boundaries or using errors.Is/As, even if the user doesn't ask about error strategy. Does not cover panic/recover patterns (see go-defensive).

766 installsAudited
GOgo-functional-options logo

go-functional-options

cxuu/golang-skills

Use when designing a Go constructor or factory function with optional configuration — especially with 3+ optional parameters or extensible APIs. Also use when building a New* function that takes many settings, even if they don't mention "functional options" by name. Does not cover general function design (see go-functions).

732 installsAudited
GOgo-interfaces logo

go-interfaces

cxuu/golang-skills

Use when defining or implementing Go interfaces, designing abstractions, creating mockable boundaries for testing, or composing types through embedding. Also use when deciding whether to accept an interface or return a concrete type, or using type assertions or type switches, even if the user doesn't explicitly mention interfaces. Does not cover generics-based polymorphism (see go-generics).

753 installsAudited