From golang-skills
Applies core Go style principles: gofmt formatting, soft line length limits, reducing nesting, avoiding unnecessary else, naked returns guidelines. Fallback for general Go style queries excluding error handling, naming, testing.
npx claudepluginhub cxuu/golang-skills --plugin golang-skillsThis skill uses the workspace's default tool permissions.
When writing readable Go code, apply these principles in order of importance:
Enforces Go code style for clarity: semantic line breaking beyond 120 chars, var vs := declarations, explicit slice/map initialization, field-named composite literals. Use for writing/reviewing Go code.
Applies Go best practices, idioms, and conventions from Effective Go guide for writing, reviewing, and refactoring idiomatic Go code.
Enforces Go coding standards from Effective Go and Go Code Review Comments, covering import ordering, naming conventions, variable declarations, struct initialization, and formatting. Use when writing or reviewing idiomatic Go code.
Share bugs, ideas, or general feedback.
When writing readable Go code, apply these principles in order of importance:
Read references/PRINCIPLES.md when resolving conflicts between clarity, simplicity, and concision, or when you need concrete examples of how each principle applies in real Go code.
Run gofmt — no exceptions. There is no rigid line length limit, but Uber suggests a soft limit of 99 characters. Break by semantics, not length — refactor rather than just wrap.
Read references/FORMATTING.md when configuring gofmt, deciding on line breaks, applying MixedCaps rules, or resolving local consistency questions.
Handle error cases and special conditions first. Return early or continue the loop to keep the "happy path" unindented.
// Bad: Deeply nested
for _, v := range data {
if v.F1 == 1 {
v = process(v)
if err := v.Call(); err == nil {
v.Send()
} else {
return err
}
} else {
log.Printf("Invalid v: %v", v)
}
}
// Good: Flat structure with early returns
for _, v := range data {
if v.F1 != 1 {
log.Printf("Invalid v: %v", v)
continue
}
v = process(v)
if err := v.Call(); err != nil {
return err
}
v.Send()
}
If a variable is set in both branches of an if, use default + override pattern.
// Bad: Setting in both branches
var a int
if b {
a = 100
} else {
a = 10
}
// Good: Default + override
a := 10
if b {
a = 100
}
A return statement without arguments returns the named return values. This is
known as a "naked" return.
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return // returns x, y
}
// Good: Small function, naked return is clear
func minMax(a, b int) (min, max int) {
if a < b {
min, max = a, b
} else {
min, max = b, a
}
return
}
// Good: Larger function, explicit return
func processData(data []byte) (result []byte, err error) {
result = make([]byte, 0, len(data))
for _, b := range data {
if b == 0 {
return nil, errors.New("null byte in data")
}
result = append(result, transform(b))
}
return result, nil // explicit: clearer in longer functions
}
See go-documentation for guidance on Named Result Parameters.
Go's lexer automatically inserts semicolons after any line whose last token is
an identifier, literal, or one of: break continue fallthrough return ++ -- ) }.
This means opening braces must be on the same line as the control structure:
// Good: brace on same line
if i < f() {
g()
}
// Bad: brace on next line — lexer inserts semicolon after f()
if i < f() // wrong!
{ // wrong!
g()
}
Idiomatic Go only has explicit semicolons in for loop clauses and to separate
multiple statements on a single line.
| Principle | Key Question |
|---|---|
| Clarity | Can a reader understand what and why? |
| Simplicity | Is this the simplest approach? |
| Concision | Is the signal-to-noise ratio high? |
| Maintainability | Can this be safely modified later? |
| Consistency | Does this match surrounding code? |