mcpField
G
go-style-core

go-style-core

github.com/cxuu开发1861.3k 次安装19 周前更新
代码仓库

关于 go-style-core

go-style-core 为编写 Go 代码提供按优先级组织的可读性与格式规范,适用于希望统一风格并改善可维护性的开发者。内容涵盖格式、控制流和返回值等实践。

主要功能

  1. 01按优先级指导代码风格
  2. 02强调 gofmt 与语义换行
  3. 03建议减少嵌套和多余分支
  4. 04说明裸返回的适用范围

适用场景

  1. 01编写易读的 Go 代码
  2. 02审查代码中的控制流与格式
  3. 03处理风格原则之间的取舍

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/cxuu/golang-skills --skill go-style-core

安装后在 Claude Code 中输入/go-style-core确认已加载。

附带文件references/FORMATTING.mdreferences/PRINCIPLES.md

详细介绍

Go 风格核心原则

资源路由

  • references/PRINCIPLES.md - 在处理清晰性、简单性、简洁性、可维护性和一致性之间的冲突时阅读。
  • references/FORMATTING.md - 在处理 gofmt、换行、空白、注释或分号时阅读。

风格原则(按优先级排序)

编写易读的 Go 代码时,请按重要性顺序应用以下原则:

优先级顺序
  1. 清晰性 — 读者无需额外上下文就能理解代码吗?
  2. 简单性 — 这是实现目标最简单的方式吗?
  3. 简洁性 — 每一行代码都有其存在的价值吗?
  4. 可维护性 — 以后修改起来容易吗?
  5. 一致性 — 这是否符合周围的代码和项目约定?

格式化

运行 gofmt——没有例外。没有严格的行长限制,但 Uber 建议将 99 个字符作为软性限制。按语义拆分,而不是按长度拆分——应重构代码,而不是只做换行。


减少嵌套

优先处理错误情况和特殊条件。尽早返回或继续循环,避免“正常流程”产生缩进。

// 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()
}
不必要的 else

如果变量在 if 的两个分支中都会赋值,请使用“默认值 + 覆盖”模式。

// Bad: Setting in both branches
var a int
if b {
    a = 100
} else {
    a = 10
}

// Good: Default + override
a := 10
if b {
    a = 100
}

裸返回

不带参数的 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
}

有关命名返回参数的指导,请参阅 go-documentation。


分号

Go 词法分析器会在以下行末自动插入分号:末尾 token 为标识符、字面量,或以下任一项:break continue fallthrough return ++ -- ) }。

这意味着左花括号必须与控制结构写在同一行:

// 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()
}

符合 Go 惯例的代码只会在 for 循环子句中显式使用分号,或用分号分隔同一行上的多条语句。


快速参考

原则核心问题
清晰性读者能理解做了什么以及为什么这样做吗?
简单性这是最简单的实现方式吗?
简洁性信噪比高吗?
可维护性以后可以安全地修改吗?
一致性这是否符合周围的代码?

相关技能

  • 命名约定:应用 MixedCaps、选择标识符名称或解决命名争议时,请参阅 go-naming
  • 错误流程:设计错误优先的守卫子句或通过提前返回减少嵌套时,请参阅 go-error-handling
  • 文档:编写文档注释、命名返回参数或包级文档时,请参阅 go-documentation
  • Lint 强制检查:使用 golangci-lint 自动执行风格检查或配置 CI 时,请参阅 go-linting
  • 代码审查:在系统化代码审查中应用风格原则时,请参阅 go-code-review
  • 日志风格:审查日志实践、选择 log 或 slog,或组织日志输出时,请参阅 go-logging

评论

支持 Markdown