go mod init 必须显式指定与 import 路径一致的模块名(如 example.com/myapp),不可省略或用相对路径;go.mod 生成后立即运行 go mod tidy;gofmt 与 goimports 需保存时自动执行;配置应绑定结构体而非全局 viper 取值。

go mod 初始化必须显式指定模块路径
不加参数直接 go mod init 会生成错误的模块名(比如 github.com/username/project),而实际你可能用的是私有 Git 地址或本地路径。后续依赖解析、go get、CI 构建都会出问题,尤其在私有仓库或 monorepo 场景下。
正确做法是:在项目根目录执行 go mod init example.com/myapp,模块路径必须与你最终 import 的路径一致——哪怕只是本地开发,也应模拟真实导入路径(如 myapp 就不行,example.com/myapp 才对)。
- 模块路径不能以
./或相对路径开头 - 如果项目托管在 Git,建议和远程 URL 的域名/路径保持一致(如
gitlab.internal/foo/bar→ 模块名设为gitlab.internal/foo/bar) -
go.mod生成后立即运行go mod tidy,它会自动补全缺失依赖并清理未使用项,但前提是import语句已写完
gofmt + goimports 必须作为保存时强制动作
仅靠人工执行 gofmt -w 或 CI 检查无法防止格式污染。Go 的代码风格是契约型的——不是“建议”,而是编译器和工具链隐含依赖的结构。缩进错位、括号换行异常、import 分组混乱,会导致 go vet 报告误报,甚至影响 go list 解析包依赖。
VS Code 用户需确认:"editor.formatOnSave": true 且 formatter 设置为 gofumpt(比原生 gofmt 更严格);同时安装 goimports 并配置 "golang.useLanguageServer": true,否则 goimports 不会在保存时自动插入/删除 import 行。
立即学习“go语言免费学习笔记(深入)”;
- 不要用
go fmt—— 正确命令是gofmt或go fmt(后者是别名,但语义易混淆) -
goimports需单独安装:go install golang.org/x/tools/cmd/goimports@latest - 禁止在
go.mod中引入gofmt或goimports作为依赖——它们是开发工具,不是运行时依赖
配置加载必须绑定结构体而非用 viper 全局取值
用 viper.GetString("db.host") 这类方式,会让配置键散落在各处,IDE 无法跳转、字段变更不报错、单元测试难 mock,且 viper 默认行为(如自动环境变量映射、大小写不敏感)会在多环境部署时引发静默覆盖。
推荐做法:定义一个顶层 Config 结构体,每个字段带 mapstructure tag,在启动时一次性从 YAML 文件解码。所有业务代码只接收该结构体指针,不接触任何全局配置对象。
- 结构体字段必须导出(首字母大写),否则
mapstructure无法赋值 - YAML 文件路径应在
main()中硬编码传入,避免依赖viper.AddConfigPath的隐式搜索逻辑 - 校验逻辑要放在解码后、服务启动前:
if c.HTTP.Port 0") }
internal/ 下包名必须与目录名完全一致且小写
Go 编译器不检查包名与目录名是否匹配,但 go list、go test 和 IDE(如 GoLand)的符号解析都依赖这个约定。一旦 internal/user/ 目录里写了 package users,就会出现 “cannot find package” 或 “ambiguous import” 错误,尤其在跨包引用时。
标准库全是小写无下划线的包名(net/http、strings、io),你的代码也该如此。别用 user_service 或 UserSvc,就用 user。
- 包名 ≠ 目录路径全名,只是最后一级:
internal/user/auth→ 包名是auth,不是user_auth - 避免复数形式:
users容易和user类型混淆,统一用单数user - 同一目录下不能存在多个
package声明——Go 不支持一个目录多个包


















