Go-08-包、模块与代码组织
本节目标:掌握 Go 的包(package)系统、模块(module)/ go.mod、init 机制,理解 import 路径解析。
1. 包(package)基础
包是 Go 基本的代码组织单元。每个 .go 文件开头必须声明 package 名:
1 | package mypkg |
同包内的多个 .go 文件 组成一个编译单元,共享私有(未导出)标识符。
1.1 包名 vs 目录名
惯例:包名和所在目录名相同(最后一段路径)。
1 | mypkg/ |
例外:main 包是入口包,目录名可以任意但 package 必须是 main。
1.2 导出规则
- 首字母大写 = 导出(public)
- 首字母小写 = 包内可见(private)
1 | package mypkg |
2. import 语法
1 | import "fmt" // 单个 |
3. go.mod 与模块(Module)
模块 = 一个或多个包的集合,有版本号,通过 go.mod 文件标识。
3.1 创建模块
1 | $ mkdir myapp && cd myapp |
生成的 go.mod:
1 | module github.com/myuser/myapp |
3.2 常用命令
1 | # 添加依赖 |
3.3 go.mod 文件结构
1 | module github.com/myuser/myapp |
4. import 路径解析规则
1 | import "github.com/gin-gonic/gin" |
Go 工具链查找顺序:
- 标准库:
fmt,os,net/http直接在$GOROOT/src找 - 模块内相对路径:
module-path/... - GOPATH/pkg/mod:第三方依赖缓存
- **vendor/**(如果存在):优先于 GOPATH
示例:
1 | module github.com/myuser/myapp |
文件 github.com/myuser/myapp/cmd/server/main.go 想 import 同模块的包:
1 | import ( |
5. internal 包(私有性)
internal 目录是个魔法:myapp/internal/foo 只能被 myapp/... 下的代码 import,外部模块看不到。
1 | github.com/myuser/myapp/ |
Go 工具会在 go build 时检查,import 别人 internal 包直接编译错误。
6. init 函数:包级初始化
1 | package redis |
init 触发时机:
- 包被 import 时(只一次)
- 多个 init 按声明顺序执行
- 依赖包的 init 先于当前包
main包的 init 在 main 函数前执行
典型用途:
- 注册驱动(
database/sql、image解码器) - 加载配置
- 启动后台 goroutine
- 设置全局状态
警告:init 里 panic 会让整个程序启动失败。
7. 包级变量 vs init 初始化
1 | // 简单情况用 var 初始化 |
8. 实战:项目结构
典型 Go 项目布局:
1 | myapp/ |
为什么这样分:
cmd/:多个可执行文件入口internal/:业务逻辑,不暴露给外部pkg/:可以独立 import 的库api/:接口契约deployments/:基础设施
9. 多模块项目(Monorepo)
1 | myorg/ |
go.work:
1 | go 1.22 |
1 | # 在 workspace 模式下 |
10. 实战:发布自己的 Go 库
1 | # 1. 初始化 |
11. 循环依赖
包 A 引用 B,B 又引用 A → 编译错误。解决方法:
1 | // 错:循环引用 |
解决 1:抽公共部分到第三个包
1 | a/ b/ common/ |
解决 2:用接口解耦
1 | // b/b.go: 不直接 import a,而是接受一个接口 |
12. 最佳实践
- 包名短而清晰:
bytes,http,time(不要util,common,helper) - 避免包级状态:少用全局变量,多用依赖注入
- 小而专的包:每个包做一件事
- import 分组:标准库 / 第三方 / 内部 用空行分隔
- 不要 import . (点导入)
- vendor 还是 module:Go 1.16+ 默认 module,不用 vendor(除非有网络限制)
小结
| 概念 | 作用 |
|---|---|
package |
代码组织单位,编译单元 |
go.mod |
模块定义 + 依赖版本 |
internal/ |
包私有性(魔法) |
init() |
包级初始化,import 时触发 |
import |
标准库、第三方、内部 |
replace |
模块替换(debug 私有 fork) |
go.work |
多模块 workspace |
最常用命令:
1 | go mod init mymodule |
下一节讲 I/O 与文件处理,Go 用 io.Reader/io.Writer 接口统一了所有 I/O。
- 本文作者: CoderSong
- 本文链接: https://jack-song-gif.github.io/2026/08/25/Go-08-包、模块与代码组织/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!