Files
cs-note/hzh/GolangStar/Go编码规范/Go编码规范.md
T

7.0 KiB
Raw Blame History

tags, create time
tags create time
go
golang
code-style
coding-standard
2026-06-07 14:30

Go 编码规范

概述

本文档整理自企业级 Go 项目开发规范,涵盖代码格式化、命名约定、错误处理、注释规范等核心方面。良好的编码规范是团队协作的基石,也是区分初级和中级开发者的关键标志。

[!question] ❓ 思考一下 在编写 Go 代码之前,你是否考虑过:为什么 Go 要强制 gofmt 而不像其他语言那样提供多种风格选择?这种"一刀切"的设计背后体现了怎样的哲学?

正文

1. 代码格式化

1.1 【必须】使用 gofmt 格式化

所有 Go 代码必须使用 gofmt 格式化,这是 Go 社区的硬性要求。

[!tip] 💡 面试技巧 面试中如果被问到"Go 如何保证代码风格统一",可以回答:Go 通过内置的 gofmt 工具强制统一格式,不需要像 Java(Google Style / Alibaba Style)或 JavaScript(Prettier / ESLint)那样额外配置,从语言层面杜绝了代码风格的争论。

1.2 【推荐】行宽控制

建议一行代码不超过 120 列,超长时合理换行。

[!warning] ⚠️ 高频陷阱 函数签名不要为了凑列数而换行!gofmt 会使签名与函数内语句对齐,反而降低可读性。

// 正确的长函数签名 —— 不换行
func (i *webImpl) GenerateAgentInstallLink(ctx context.Context, req *pb.GenerateAgentInstallLinkRequest) (*pb.GenerateAgentInstallLinkResponse, error) {
    // ...
}

// 错误的长字符串拼接 —— 不要这样做!
pubkey := "ssh-rsa AAAAB3NzaC1yc2E..." +
    "zi2SqaZVeeXmsF5GAGFJcUylujr78Wf6od8//SApYx8RCSkRhGo8cTsxADlBCoTttJvk6Ocmy+uqEFXulsI0j+nh2x352eCExlDSqr0Me0J0LIGq/u9eqwhNN5k"

// 正确做法:多行文本用原始字符串字面量
tmpl := `some
long
tedious
template`

2. Import 规范

2.1 【必须】使用 goimports

  • 标准包永远在最上面的第一组
  • 内部包与第三方包之间用空行分隔
  • 不使用相对路径引入包
import (
	// standard package & inner package
	"encoding/json"
	"myproject/models"
	"strings"

	// third-party package
	"github.com/opentracing/opentracing-go"

	// anonymous import package
	// import filesystem storage driver
	_ "git.code.oa.com/org/repo/pkg/storage/filesystem"
)

[!note] 📝 核心考点

  • 带域名的包名都属于第三方包(如 github.com/xxx/xxx),无论是否当前项目内部
  • 匿名导入 _ 通常用于执行包的 init() 函数(如注册驱动)

3. 错误处理

3.1 【必须】error 作为最后一个返回值

// 正确
func do() (int, error) { ... }

// 错误
func do() (error, int) { ... }

3.2 【必须】独立错误流

// 推荐:尽早 return
if err != nil {
    return err
}
// normal code here

// 不推荐:else 嵌套
if err != nil {
    // error handling
} else {
    // normal code
}

3.3 【必须】panic 的使用场景

[!warning] ⚠️ 高频陷阱 不要用 panic 处理用户输入错误!panic 仅用于:

  1. 不变量断言(invariant assertion)
  2. init() 函数中初始化失败
  3. 全局变量初始化中调用 MustXXX 系列函数
// 正确:对不变量断言
func readText(n Node) string {
    switch n := n.(type) {
    case *TextNode:
        return n.Text
    case *CommentNode:
        return n.Comment
    default:
        panic(fmt.Errorf("unexpected node type: %T", n))
    }
}

// 错误:用户输入应该返回 error
v, err := strconv.Atoi(userInputFromKeyboard)
if err != nil {
    panic(fmt.Errorf("invalid user input: %v", err)) // DON'T!
}

3.4 【必须】recover 的正确姿势

defer func() {
    e := recover() // 注意:返回 interface{},不要命名为 err
    if e != nil {
        err, ok := e.(FatalError)
        if !ok {
            panic(e) // 继续抛出不认识的异常
        }
        // 处理已知类型的 panic
    }
}()

4. 命名规范

[!tip] 💡 面试技巧 面试中被问"go 命名规范"时,可以总结为:驼峰式 + 首字母大小写控制可见性 + 专有名词保持原写法。举例说明 apiClient(私有)vs APIClient(导出)。

规则 要点
包名 小写、简短、不与标准库冲突、避免 util/common/misc
文件名 小写 + 下划线分割
结构体 驼峰、名词短语、避免 Info/Data
接口 单方法以 -er 结尾(Reader/Writer)
变量/常量 驼峰、短命名优先(局部变量 c > lineCount)
函数 驼峰、首字母大小写控制导出

5. 控制结构

5.1 【推荐】if 初始化语句

if err := file.Chmod(0664); err != nil {
    return err
}

5.2 【必须】switch 必须有 default

switch os := runtime.GOOS; os {
case "darwin":
    fmt.Println("OS X.")
case "linux":
    fmt.Println("Linux.")
default:
    fmt.Printf("%s.\n", os)
}

5.3 【必须】range 丢弃不需要的值

for key := range m {       // 只需要 key
    delete(m, key)
}
for _, v := range slice {   // 只需要 value
    _ = v
}

6. 注释规范

[!question] ❓ 思考一下 Go 要求每个导出的名字都必须有注释,但非导出类型的方法可以没有。你觉得这种设计反映了什么考量?

必填注释清单:

  • 包注释(// Package xxx)
  • 导出的结构体和接口
  • 导出的函数和方法
  • 导出的常量和变量
  • 导出的类型定义和类型别名

7. 函数设计

规则 约束
参数数量 不超过 5 个
传递方式 优先值传递,非指针传递
map/slice/chan/interface 不要传指针
文件长度 不超过 800 行
函数长度 不超过 80 行
嵌套深度 不超过 4 层

8. defer 使用

[!warning] ⚠️ 高频陷阱 禁止在循环中使用 defer! 因为 defer 要到函数结束时才统一调用,会导致资源堆积。

// 错误:循环中 defer
for _, v := range values {
    fields, _ := db.Query(v)
    defer fields.Close() // 所有 Close 直到函数结束才执行!
}

// 正确:闭包内 defer
for _, v := range values {
    func() {
        fields, _ := db.Query(v)
        defer fields.Close() // 立即关联到当前迭代
    }()
}

9. 依赖管理

  • Go 1.11+ 必须使用 go modules
  • go.sum 必须提交,不要加入 .gitignore
  • 不建议提交 vendor 目录

附录:常用工具速查表

[!tip] 💡 工具速查

工具 作用
gofmt 自动格式化代码,保证格式统一
goimports 在 gofmt 基础上自动增删 import
go vet 静态分析,检测多余代码、提前 return 等
golint 检测不规范的地方(已迁移至 staticcheck)

关联笔记