Go代码质量取决于可读性、可维护性与协作效率,核心在于命名清晰、错误处理得当、接口精简、工具链完备及持续反思。

Go 代码好不好,不看炫技,只看别人能不能不查文档就看懂、改得安心、加得顺手——这背后是命名、结构、错误处理和接口设计的日常选择,不是靠背规范条文。
变量和函数名怎么起才不让人猜
Go 不强制大驼峰,反而鼓励小写字母+下划线分隔的清晰表达,但更关键的是「名即其责」。比如 userID 比 id 好,parseJSONConfig 比 doParse 好,哪怕多打几个字母。
常见错误现象:err 被反复覆盖导致上游 panic;tmp、v、data 这类变量在 50 行函数里出现 7 次,没人知道哪个是哪个。
- 导出标识符(首字母大写)用
PascalCase,如HTTPClient、UserID - 包内私有变量/函数统一用
snake_case或lowerCamel,保持全包一致,别混用 - 布尔变量优先用
is/has/can开头,如isValid、hasPermission,避免valid这种歧义名 - 接收器名别叫
self或this,用 1–2 字缩写,如s *Server、c *Cache
error 处理不是 if err != nil { return err } 的复制粘贴
Go 的错误是值,不是控制流。直接返回裸 err 往往丢失上下文;用 fmt.Errorf("xxx: %w", err) 包裹时,必须确认上游是否真需要这个层级的封装。
使用场景:HTTP handler 中,数据库查询失败,该返回 http.StatusServiceUnavailable 还是透传底层 sql.ErrNoRows?取决于调用方是否要区分「没数据」和「连不上库」。
- 不要在中间层无意义地
fmt.Errorf("%v", err)—— 丢掉了%w,断了错误链 - 导出函数返回 error 时,若错误类型需被判断(如重试逻辑),定义具体错误变量,如
var ErrRateLimited = errors.New("rate limited") - 日志中打印 error 前,先用
errors.Is(err, xxx)或errors.As(err, &e)判断类型,避免对nil调用Error()panic - 测试中验证错误内容,别只 check
err != nil,用assert.ErrorContains(t, err, "timeout")(testify)或strings.Contains(err.Error(), "timeout")
interface 定义越小越好,但别小到只剩一个方法
Go 接口不是为了“解耦”而抽象,而是为「谁用、怎么用」服务。一个 Reader 接口只有 Read([]byte) (int, error) 是合理的,但为单个函数造个 Doer 接口就过头了。
容易踩的坑:提前定义大接口(如 UserService 含 8 个方法),结果测试时不得不 mock 全部,或者某次重构只动了其中 1 个方法,却要改所有实现。
- 按调用方视角定义接口:handler 需要什么,就定义什么,而不是按「领域对象」画接口
- 接口名以
er结尾(Writer、Closer),除非语义明确(如Conn、FS) - 避免在接口里放非核心行为,比如
Log() error或Validate() error—— 这些该由调用方决定何时做 - 包内私有接口不用导出,别为了「看起来整洁」把
type reader interface{ Read([]byte) (int, error) }放在 public API 里
go fmt 和 go vet 是底线,不是终点
go fmt 只管空格换行,go vet 查明显误用(如 printf 参数错位),但它们不拦得住逻辑 bug、资源泄漏、竞态或坏的抽象。
真正影响长期维护的,是那些工具不报错但人看了皱眉的地方:比如一个 200 行的 HandleRequest 函数里嵌了 4 层 if err != nil,或者 map[string]interface{} 在 3 个函数间传来传去最后用 json.Marshal 硬塞。
- CI 里必须跑
go vet -tags=unit+staticcheck(比go vet更严) - 禁止
gobindata、go:generate生成的代码进 git,除非团队全员熟悉其更新流程 - 第三方依赖升级前,用
go list -u -m all和go mod graph | grep xxx看真实依赖路径,避免间接引入冲突版本 - 性能敏感路径(如高频 HTTP middleware)别依赖
reflect或fmt.Sprint,用strconv和预分配bytes.Buffer
最难的不是记住「该怎么做」,是在写第 5 个 if err != nil 时,停下来想一句:这里是不是该拆个函数?这个 error 类型,下游真的会检查吗?
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











