Skillshub go-control-flow
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).
git clone https://github.com/ComeOnOliver/skillshub
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/cxuu/golang-skills/go-control-flow" ~/.claude/skills/comeonoliver-skillshub-go-control-flow && rm -rf "$T"
skills/cxuu/golang-skills/go-control-flow/SKILL.mdGo Control Flow
Read references/SWITCH-PATTERNS.md when using switch statements, type switches, or break with labels
Read references/BLANK-IDENTIFIER.md when using
, blank identifier imports, or compile-time interface checks_
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:
- The declaration is in the same scope as the existing
v - The value is assignable to
v - 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 —
is the byte offseti - 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.
Verify interface compliance at compile time:
var _ io.Writer = (*MyType)(nil).
See go-interfaces for the interface satisfaction check pattern.
Quick Reference
| Pattern | Go Idiom |
|---|---|
| If initialization | |
| Early return | Omit when if body returns |
| Redeclaration | reassigns if same scope + new var |
| Shadowing trap | in inner scope creates new variable |
| Parallel assignment | |
| Expression-less switch | |
| Comma cases | |
| No fallthrough | Default behavior (explicit if needed) |
| Break from loop in switch | |
| Discard value | |
| Side-effect import | |
| Interface check | |
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:=