npx skills add https://github.com/cxuu/golang-skills --skill go-style-core规范性:根据 Google 的权威 Go 风格指南,此指导是必需的。
编写可读的 Go 代码时,请按重要性顺序应用这些原则:
代码的目的和原理必须对读者清晰。
// 良好:目的清晰
func (c *Config) WriteTo(w io.Writer) (int64, error)
// 不佳:不清晰,重复了接收器
func (c *Config) WriteConfigTo(w io.Writer) (int64, error)
代码应以尽可能简单的方式实现目标。
简洁的代码:
最少机制原则:优先使用标准工具:
代码应具有高信噪比。
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
// 良好:常见惯用法,高信噪比
if err := doSomething(); err != nil {
return err
}
// 良好:对特殊情况增强信号
if err := doSomething(); err == nil { // 如果没有错误
// ...
}
代码被修改的次数远多于编写的次数。
可维护的代码:
// 不佳:隐藏了关键细节
if user, err = db.UserByID(userID); err != nil { // = 与 :=
// 良好:明确且清晰
u, err := db.UserByID(userID)
if err != nil {
return fmt.Errorf("invalid origin user: %s", err)
}
user = u
代码的外观和行为应与代码库中的类似代码保持一致。
所有 Go 源文件必须符合 gofmt 的输出格式。没有例外。
# 格式化一个文件
gofmt -w myfile.go
# 格式化目录中的所有文件
gofmt -w .
来源:Effective Go
Go 需要的括号比 C 和 Java 少。控制结构(if、for、switch)的语法中没有括号。运算符优先级层次更短更清晰,因此 x<<8 + y<<16 的含义正如其间距所暗示的那样——与其他语言不同。
Go 使用 MixedCaps 或 mixedCaps,从不使用下划线:
// 良好
MaxLength // 导出的常量
maxLength // 未导出的常量
userID // 变量
// 不佳
MAX_LENGTH // 不使用 snake_case
max_length // 不使用下划线
例外情况:
TestFoo_BarGo 中没有严格的行长度限制,但应避免过长的行。Uber 建议软限制为 99 个字符。
综合:Google + Uber + Go Wiki CodeReviewComments 指导
指导原则:
按语义换行,而非长度:
建议性:Go Wiki CodeReviewComments
当行较长但更易读时(例如,重复的行),不要仅仅为了保持行短而添加换行符。换行应基于你正在编写的内容,而不是基于行长度。
长行通常与长名称相关。如果你发现行太长,考虑名称是否可以更短。去掉长名称通常比换行更有帮助。
此建议同样适用于函数长度——没有"函数永远不能超过 N 行"的规则,但确实存在函数过长的情况。解决方案是改变函数边界的位置,而不是计算行数。
// 不佳:任意在行中间换行
func (s *Store) GetUser(ctx context.Context,
id string) (*User, error) {
// 良好:所有参数在各自的行上
func (s *Store) GetUser(
ctx context.Context,
id string,
) (*User, error) {
当风格指南没有规定时,应与附近的代码保持一致:
有效的局部选择:
%s 还是 %v无效的局部覆盖:
来源:Uber Go Style Guide
首先处理错误情况和特殊条件。尽早返回或继续循环,以保持"快乐路径"不缩进。
// 不佳:深度嵌套
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)
}
}
// 良好:平坦结构,提前返回
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()
}
来源:Uber Go Style Guide
如果一个变量在 if 的两个分支中都被设置,使用默认值 + 覆盖的模式。
// 不佳:在两个分支中设置
var a int
if b {
a = 100
} else {
a = 10
}
// 良好:默认值 + 覆盖
a := 10
if b {
a = 100
}
建议性:Go Wiki CodeReviewComments
不带参数的 return 语句会返回已命名的返回值。这被称为"裸"返回。
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return // 返回 x, y
}
// 良好:小型函数,裸返回清晰
func minMax(a, b int) (min, max int) {
if a < b {
min, max = a, b
} else {
min, max = b, a
}
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 // 明确:在较长的函数中更清晰
}
有关命名结果参数的指导,请参阅 go-documentation。
| 原则 | 关键问题 |
|---|---|
| 清晰性 | 读者能理解是什么和为什么吗? |
| 简洁性 | 这是最简单的方法吗? |
| 精炼性 | 信噪比高吗? |
| 可维护性 | 以后可以安全地修改吗? |
| 一致性 | 这与周围的代码匹配吗? |
go-naminggo-error-handlinggo-documentationgo-testinggo-defensivego-performancego-linting每周安装量
136
代码仓库
GitHub 星标数
34
首次出现
2026 年 1 月 27 日
安全审计
安装于
gemini-cli126
github-copilot126
codex126
opencode125
kimi-cli122
amp122
Normative : This guidance is required per Google's canonical Go style guide.
When writing readable Go code, apply these principles in order of importance:
The code's purpose and rationale must be clear to the reader.
What : Use descriptive names, helpful comments, and efficient organization
Why : Add commentary explaining rationale, especially for nuances
View clarity through the reader's lens, not the author's
Code should be easy to read, not easy to write
// Good: Clear purpose func (c *Config) WriteTo(w io.Writer) (int64, error)
// Bad: Unclear, repeats receiver func (c *Config) WriteConfigTo(w io.Writer) (int64, error)
Code should accomplish goals in the simplest way possible.
Simple code:
Least Mechanism Principle : Prefer standard tools:
Code should have high signal-to-noise ratio.
Avoid repetitive code
Avoid extraneous syntax
Avoid unnecessary abstraction
Use table-driven tests to factor out common code
// Good: Common idiom, high signal if err := doSomething(); err != nil { return err }
// Good: Signal boost for unusual case if err := doSomething(); err == nil { // if NO error // ... }
Code is edited many more times than written.
Maintainable code:
Is easy for future programmers to modify correctly
Has APIs that grow gracefully
Uses predictable names (same concept = same name)
Minimizes dependencies
Has comprehensive tests with clear diagnostics
// Bad: Critical detail hidden if user, err = db.UserByID(userID); err != nil { // = vs :=
// Good: Explicit and clear u, err := db.UserByID(userID) if err != nil { return fmt.Errorf("invalid origin user: %s", err) } user = u
Code should look and behave like similar code in the codebase.
All Go source files must conform to gofmt output. No exceptions.
# Format a file
gofmt -w myfile.go
# Format all files in directory
gofmt -w .
Source : Effective Go
Go needs fewer parentheses than C and Java. Control structures (if, for, switch) don't have parentheses in their syntax. The operator precedence hierarchy is shorter and clearer, so x<<8 + y<<16 means what the spacing suggests—unlike in other languages.
Go uses MixedCaps or mixedCaps, never underscores:
// Good
MaxLength // exported constant
maxLength // unexported constant
userID // variable
// Bad
MAX_LENGTH // no snake_case
max_length // no underscores
Exceptions:
TestFoo_BarThere is no rigid line length limit in Go, but avoid uncomfortably long lines. Uber suggests a soft limit of 99 characters.
Combined : Google + Uber + Go Wiki CodeReviewComments guidance
Guidelines:
Break by semantics, not length :
Advisory : Go Wiki CodeReviewComments
Don't add line breaks just to keep lines short when they are more readable long (e.g., repetitive lines). Break lines because of what you're writing, not because of line length.
Long lines often correlate with long names. If you find lines are too long, consider whether the names could be shorter. Getting rid of long names often helps more than wrapping lines.
This advice applies equally to function length—there's no rule "never have a function more than N lines", but there is such a thing as too long. The solution is to change where function boundaries are, not to count lines.
// Bad: Arbitrary mid-line break
func (s *Store) GetUser(ctx context.Context,
id string) (*User, error) {
// Good: All arguments on own lines
func (s *Store) GetUser(
ctx context.Context,
id string,
) (*User, error) {
When the style guide is silent, be consistent with nearby code:
Valid local choices:
%s vs %v for error formattingInvalid local overrides:
Source : Uber Go Style Guide
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()
}
Source : Uber Go Style Guide
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
}
Advisory : Go Wiki CodeReviewComments
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
}
OK in small functions : Naked returns are fine in functions that are just a handful of lines
Be explicit in medium+ functions : Once a function grows to medium size, be explicit with return values for clarity
Don't name results just for naked returns : Clarity of documentation is always more important than saving a line or two. Don't name result parameters just because it enables naked returns
// 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.
| 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? |
go-naminggo-error-handlinggo-documentationgo-testinggo-defensivego-performancego-lintingWeekly Installs
136
Repository
GitHub Stars
34
First Seen
Jan 27, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
gemini-cli126
github-copilot126
codex126
opencode125
kimi-cli122
amp122
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
106,200 周安装