agentsclimarketplace

Go control flow

Skill muratmirgun/gophers/skills/go-control-flow

26 production-grade Go skills for Claude Code, Gemini CLI, and opencode.

Install
npx -y skills add muratmirgun/gophers --skill go-control-flow

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 8 stars8 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

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

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

5.5 KB, as published. Nobody here has run it

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

SituationUse
New variable, scoped to the checkif v, err := f(); err != nil
Reusing an outer variableplain = (avoid := to prevent shadowing)
At least one new + reuse of outer:= is fine (same scope only)
Wanted zero valuevar 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 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 for expression-less switches, comma cases, fallthrough, and type switches.

Anti-Patterns

Anti-patternWhy it hurtsDo this instead
} else { return ... } after a returning ifPointless nestingDrop else; let the happy path stay flat
if _, err := f(); err == nil { ... } then use the valueValue is out of scopeMove the := outside the if
:= in inner scope reassigning outer varSilently shadowsUse = (declare the new locals separately)
Iterating a map and relying on orderOrder is randomizedSort keys explicitly
break inside switch expecting to exit forOnly exits switchUse labeled break Label
_ = doSomething() to silence an errorReal failures vanishHandle 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

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.