Loading...
Loading...
Go control flow idioms from Effective Go. Covers if with initialization, omitting else for early returns, for loop forms, range, switch without fallthrough, type switch, and blank identifier patterns. Use when writing conditionals, loops, or switch statements in Go.
npx skill4agent add cxuu/golang-skills go-control-flowSource: Effective Go. Go's control structures are related to C but differ in important ways. Understanding these differences is essential for writing idiomatic Go code.
dowhileforifif x > 0 {
return y
}ifswitch// Good: err scoped to if block
if err := file.Chmod(0664); err != nil {
log.Print(err)
return err
}ifbreakcontinuegotoreturnelse// Good: no else, success path at left margin
f, err := os.Open(name)
if err != nil {
return err
}
codeUsing(f)// Bad: else clause buries normal flow
f, err := os.Open(name)
if err != nil {
return err
} else {
codeUsing(f) // unnecessarily indented
}// Good: guard clauses eliminate errors early
f, err := os.Open(name)
if err != nil {
return err
}
d, err := f.Stat()
if err != nil {
f.Close()
return err
}
codeUsing(f, d):=f, err := os.Open(name) // declares f and err
// ...
d, err := f.Stat() // declares d, reassigns err (not a new err)v:=vverr// Good: err reused across multiple calls
data, err := fetchData()
if err != nil {
return err
}
result, err := processData(data) // err reassigned, result declared
if err != nil {
return err
}v:=// Bad: accidental shadowing
var err error
if condition {
x, err := someFunc() // this err shadows the outer err!
// outer err remains nil
}forwhile// C-style for (only form with semicolons)
for init; condition; post { }
// While-style (condition only)
for condition { }
// Infinite loop
for { }range// Iterate with key and value
for key, value := range oldMap {
newMap[key] = value
}
// Key/index only (drop the second variable)
for key := range m {
if key.expired() {
delete(m, key)
}
}
// Value only (use blank identifier for index)
for _, value := range array {
sum += value
}range// Reverse a slice
for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
a[i], a[j] = a[j], a[i]
}++--switchbreakswitchtrueif-else-if// Good: expression-less switch for ranges
func unhex(c byte) byte {
switch {
case '0' <= c && c <= '9':
return c - '0'
case 'a' <= c && c <= 'f':
return c - 'a' + 10
case 'A' <= c && c <= 'F':
return c - 'A' + 10
}
return 0
}func shouldEscape(c byte) bool {
switch c {
case ' ', '?', '&', '=', '#', '+', '%':
return true
}
return false
}breakLoop:
for n := 0; n < len(src); n += size {
switch {
case src[n] < sizeOne:
break // breaks switch only
case src[n] < sizeTwo:
if n+1 >= len(src) {
break Loop // breaks out of for loop
}
}
}.(type)switch v := value.(type) {
case nil:
fmt.Println("value is nil")
case int:
fmt.Printf("integer: %d\n", v) // v is int
case string:
fmt.Printf("string: %q\n", v) // v is string
case bool:
fmt.Printf("boolean: %t\n", v) // v is bool
default:
fmt.Printf("unexpected type %T\n", v)
}v := value.(type)case int, int64:_/dev/null// Only need the error
if _, err := os.Stat(path); os.IsNotExist(err) {
fmt.Printf("%s does not exist\n", path)
}
// Only need the value (discard ok)
value := cache[key] // simpler: just use single-value form
_, present := cache[key] // when you only need presence check// Bad: ignoring error will crash if path doesn't exist
fi, _ := os.Stat(path)
if fi.IsDir() { // nil pointer dereference if path doesn't exist
// ...
}import (
"fmt"
"io"
)
var _ = fmt.Printf // silence unused import (remove before committing)
var _ io.Reader
func main() {
fd, _ := os.Open("test.go")
_ = fd // silence unused variable
}init()import _ "net/http/pprof" // registers HTTP handlers
import _ "image/png" // registers PNG decoder// Verify that *MyType implements io.Writer
var _ io.Writer = (*MyType)(nil)
// Verify that MyHandler implements http.Handler
var _ http.Handler = MyHandler{}| Pattern | Go Idiom |
|---|---|
| If initialization | |
| Early return | Omit |
| Redeclaration | |
| C-style for | |
| While-style | |
| Infinite loop | |
| Range with key+value | |
| Range value only | |
| Range key only | |
| Parallel assignment | |
| Expression-less switch | |
| Comma cases | |
| No fallthrough | Default behavior (explicit |
| Break from loop in switch | |
| Type switch | |
| Discard value | |
| Side-effect import | |
| Interface check | |