Go 工程基础¶
学习目标¶
学完本章后,学习者应该能够:
- 安装和管理 Go 版本。
- 理解 Go workspace、Go module、包管理和项目组织。
- 熟练使用
go run、go build、go test、go mod、go fmt、go vet。 - 能搭建一个可维护的 Go 后端项目骨架。
Go module¶
Go module 是 Go 当前主流依赖管理方式。一个项目通常从 go.mod 开始:
常用命令:
go mod tidy 会移除无用依赖,补齐缺失依赖。
常用 go 命令¶
| 命令 | 用途 |
|---|---|
go run |
编译并运行 |
go build |
编译 |
go test |
运行测试 |
go test -race |
检查数据竞争 |
go fmt / gofmt |
格式化 |
go vet |
静态检查常见问题 |
go mod tidy |
整理依赖 |
go list |
查看包信息 |
这些命令应该进入日常开发习惯,而不是等 CI 报错再处理。
项目组织¶
一个小型后端项目可以先保持简单:
apikey/
cmd/server/main.go
internal/config/
internal/httpapi/
internal/service/
internal/repository/
internal/domain/
pkg/
go.mod
README.md
internal/ 下的包不能被项目外部直接导入,适合放业务内部代码。pkg/ 只放真的需要对外复用的包,不要把所有代码都塞进去。
包设计¶
包名应该简短、清晰,表达能力而不是文件夹层级。
好习惯:
- 包内名字不要重复包名。
- 避免
utils、common变成垃圾桶。 - 包之间依赖方向要稳定。
- 小包不等于每个文件一个包。
Go 后端实际应用例子¶
例子一:Makefile 或脚本统一命令¶
即使在 Windows 上开发,也可以在 README 中明确命令:
统一命令能减少“我本地可以”的协作成本。
例子二:配置入口集中管理¶
type Config struct {
HTTPAddr string
DBDSN string
}
func LoadConfig() Config {
return Config{
HTTPAddr: getenv("HTTP_ADDR", ":8080"),
DBDSN: os.Getenv("DB_DSN"),
}
}
配置读取集中管理,后续接入环境变量、配置文件或配置中心都更容易。
常见误区¶
- 误区一:一开始就搭很复杂的目录。
目录结构应该服务于业务复杂度。小项目先简单,边界清晰后再拆。
- 误区二:
pkg是所有公共代码目录。
pkg 应该放真正希望外部项目导入的包。内部业务代码优先放 internal。
- 误区三:依赖报错就手动改
go.sum。
通常应该通过 go mod tidy、go get 等命令管理依赖,不要手动乱改。
实战任务¶
创建一个最小 Go HTTP 服务项目:
- 使用 Go module。
- 入口放在
cmd/server/main.go。 - 提供
/healthz接口。 - README 写出运行、测试、构建命令。
- 运行
go fmt、go vet、go test。
参考答案
目录可以这样组织:
main.go 可以使用标准库 net/http:
package main
import (
"log"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
})
log.Fatal(http.ListenAndServe(":8080", mux))
}
README 至少写清楚 go run ./cmd/server、go test ./...、go build ./cmd/server。
面试题¶
1. Go module 解决什么问题?¶
参考答案
Go module 解决依赖声明、版本选择、可复现构建和模块边界问题。go.mod 描述模块路径、Go 版本和依赖版本,go.sum 记录依赖校验信息。
它让项目不再依赖 GOPATH 固定目录,也方便 CI 和团队成员使用一致依赖。
2. internal 目录有什么作用?¶
参考答案
internal 是 Go 的特殊目录。放在 internal 下的包只能被其父目录树内的代码导入,外部模块无法直接导入。
它适合放业务内部实现,帮助控制包的可见性,避免内部代码被外部依赖后难以重构。
3. go fmt 和 go vet 分别做什么?¶
参考答案
go fmt 负责统一代码格式,减少风格争论。go vet 是静态检查工具,用于发现一些可疑代码,例如格式化参数不匹配、不可达代码、错误的 struct tag 等。
两者都应该进入日常开发和 CI。