Go代码必须经gofmt -w格式化、包名严格小写单字且与目录一致、error必须末位返回并立即处理、context.Context须为首参且不可存入struct。

没跑过 gofmt -w 的 Go 代码,不算写完。这不是风格偏好,是协作硬门槛——所有缩进、换行、括号位置、import 分组,全由它定;手动调格式只会被 CI 打回、引发 diff 冲突、拖慢 PR 流程。
gofmt 是强制起点,不是可选项
Go 官方不提供配置项,gofmt 是硬编码规则:tab 缩进、操作符前后空格、if/for 括号不换行、import 按字母分组(标准库 / 第三方 / 本地包)。常见错误包括:
- 手写对齐变量声明,比如
var name string = "a"和var age int = 18——gofmt会抹掉空格,变成紧凑单列 - 把
import拆成多行并手动排序 ——goimports(推荐替代原生gofmt)会自动重排+增删引用 - 用相对路径 import,如
import "../net"—— 必须用完整模块路径,如import "github.com/myorg/myproj/net"
建议编辑器绑定保存时自动执行 goimports:go install golang.org/x/tools/cmd/goimports@latest,比原生 gofmt 多出 import 管理能力。
package 名必须小写、单字、与目录名完全一致
Go 的包名不是标签,而是文件系统路径的映射。比如 github.com/foo/bar/internal/auth/jwt 目录下,package 声明只能是 package jwt,不能是 package auth_jwt 或 package AuthJWT。违反会导致:
立即学习“go语言免费学习笔记(深入)”;
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
-
go build报错:found packages main and jwt in ./internal/auth/jwt - 其他包
import "github.com/foo/bar/internal/auth/jwt"后无法访问jwt.DoSomething(),因为符号解析失败 - ID E 补全失效、跳转断链(尤其在
internal或vendor嵌套场景)
Google 风格指南明确反对复数或下划线:不用 models、utils、user_handlers,而用 model、util、user。
error 必须最后一个返回,且 err != nil 后必须终止流程
Go 不抛异常,error 是契约的一部分。函数签名如 func Open(name string) (*File, error),顺序不能变。容易踩的坑:
- 把
error放第一个返回值,导致调用方用_, err := f()忽略关键返回值 -
if err != nil后没return或panic,继续执行后续逻辑(比如数据库 query 后没检查 err 就直接用结果) - 用
log.Fatal替代传播,切断调用链上下文,上游无法做重试或分类处理 - 多层调用中只在最外层检查
error,中间层忽略,导致原始错误堆栈丢失
正确做法:每个 err != nil 分支必须立即退出当前函数;若要传递,用 fmt.Errorf("xxx: %w", err) 包裹,保留原始 error 链。
context.Context 永远放第一个参数,别塞进 struct
context.Context 是 Go 中超时、取消、跨层传值的事实标准,但它的使用有严格约束:
- 必须是函数第一个参数,如
func DoWork(ctx context.Context, id string) error;放在中间或末尾会破坏生态工具(如 tracing 注入、timeout 透传) - 绝不能把
ctx存进 struct 字段里(比如type Service struct { ctx context.Context }),这会让生命周期失控,造成 goroutine 泄漏或静默超时失效 - 不要用
context.Background()或context.TODO()“先占位”,除非你 100% 确认该函数永远不参与 cancel/timeout 链
真正难的是 context 的“传递时机”——不是每个函数都需要它,但一旦涉及 I/O、网络、数据库、下游调用,就必须显式接收并向下传。漏传一层,整条链就断了。

















