工具链与模块
工具链与模块 · 阅读后完成下方实验与检查题,再用「标记完成」记录进度。
学习目标
这课解决「从空目录到可维护的 Go 工程」这第一步:建立模块、认识包与入口,把 go run、gofmt、go vet、go test 四个命令纳入日常,后面每课都在这个底座上盖楼。
问题场景
你准备动手写书签服务 p7-go-bookmark。文件夹建好了,随手写了个 main.go,却发现没人告诉你怎么编译;从网上抄的代码 import 了别人的包,也不知道依赖记在哪里。Go 的答案很固定:模块管依赖、包管组织、go 命令管一切流程,顺序错了后面每课都要还债。
核心解释
先建模块,再写代码:
mkdir bookmark && cd bookmark
go mod init bookmark
go mod init 生成的 go.mod 是模块的身份证,声明模块名和 Go 版本:
module bookmark
go 1.26
模块名是包引用路径的前缀,以后内部包会写成 bookmark/internal/store 这样的形式。可执行程序有一条固定约定:package main + func main,这是编译器认的唯一入口:
package main
import "fmt"
func main() {
fmt.Println("bookmark service, go 1.26")
}
四个命令覆盖日常循环,值得背下来:
go run .:编译并运行当前包,改完立即验证go build ./...:全量编译检查,能过说明没有编译错误gofmt -l .:列出格式不规范的文件。Go 只有官方一种格式,不要手调空格go vet ./...:静态检查可疑代码,比如 Printf 参数类型不匹配
依赖不手动改 go.mod:代码里 import 之后跑 go mod tidy,它自动把需要的包写进 require 并下载;删掉 import 再 tidy,依赖也会被摘掉。测试命令 go test ./... 现在跑会显示 no test files,这是正常的,G13 开始它就有活了。
示例拆解
把上面几步连起来跑:
go run .
# bookmark service, go 1.26
gofmt -l .
# 无输出 = 全部合规
go vet ./...
# 无输出 = 静态检查通过
几个细节:go run . 里的点表示「当前目录这个包」,比写文件名稳,以后一个包多个文件也不用改命令;gofmt 和 vet 成功时都是安静的,检查类命令以「无输出」为通过信号;./... 表示「所有子包」,模块长大之后这条命令依然全量覆盖。构建产物也值得看一眼:go build . 会在目录里留下一个以模块名命名的可执行文件,go run 则是编完直接跑不留产物。
动手任务
- 从空目录执行
go mod init bookmark,写出最小 main.go 并go run .跑通。 - 把
fmt.Printf("count=%d", "not-a-number")写进 main,先go build ./...(能通过),再go vet ./...(会报警),体会两者分工。 - 打乱 main.go 的缩进和空格,跑
gofmt -w .让工具自动改回来,确认工具比手调靠谱。
常见错误
- 在没有 go.mod 的目录里 go run:报 go.mod file not found,Go 项目必须先 init 模块。
- import 了第三方包却没跑 go mod tidy:编译报 no required module provides package。
- 手动编辑 go.mod 的 require 行却不跑 tidy:版本对不上,构建直接失败。
- 把 go vet 当格式化工具:vet 查逻辑可疑点,格式问题归 gofmt,两者互补不能替代。
检查与复盘
完成下方检查题。自查清单:
- 能在 5 分钟内从空目录做到 go run 跑通
- 说得出 go run、go build、go test 分别在什么时候用
- 格式和静态检查交给 gofmt / go vet,不靠肉眼
参考资料
- Go 官方:模块开发指南 —— go mod init 与 go.mod 的权威说明
- Go 命令文档 —— run/build/vet/test 每个命令的完整参数
- 标准库 fmt —— Printf 动词参考
读完这一课了?
标记完成后,工作台会安排接下来的学习。