主题
第10章 包管理与 Go Module
📚 学习目标:理解包是什么、如何组织代码、用 Go Module 管理依赖。
🎯 章节导读
如果说前 9 章学的是"如何写一段 Go 代码",那这一章学的就是如何组织一个 Go 项目。
生活类比:
- package(包):相当于一个文件夹里的"工具箱",里面放着相关的工具
- import(导入):相当于"从超市买工具"
- go.mod:相当于"购物清单",记录用了哪些工具、什么版本
📦 1. 包(package)的概念
1.1 一个文件 = 一个 package?
不对!一个文件夹下的所有 .go 文件必须属于同一个 package。
mathx/
add.go // package mathx
sub.go // package mathx
multi.go // package mathx如果同目录下文件 package 不同,编译会报错。
1.2 main 包
只有 package main 且包含 func main() 的程序才能编译成可执行文件。
go
package main
import "fmt"
func main() {
fmt.Println("Hello")
}其他名字的 package 都是库,被别人引用。
1.3 公开 vs 私有:首字母大小写
Go 没有 public/private 关键字,靠标识符首字母大小写控制:
| 首字母 | 可见性 |
|---|---|
| 大写(Add、Name) | 包外可见(导出) |
| 小写(add、name) | 仅包内可见 |
go
package mathx
func Add(a, b int) int { return a + b } // 别的包能调用
func sub(a, b int) int { return a - b } // 只能本包用📥 2. import:导入包
2.1 三种用法
go
// 单个导入
import "fmt"
// 多个导入(推荐)
import (
"fmt"
"strings"
"myproject/utils"
)
// 别名导入
import (
f "fmt" // 用 f 代替 fmt
. "math" // 后续可省略 math. 前缀(不推荐)
_ "image/png" // 仅执行 init(),不引用
)2.2 标准库 vs 第三方 vs 本项目
go
import (
// 1. 标准库(直接写名字)
"fmt"
"net/http"
// 2. 第三方库(完整路径)
"github.com/gin-gonic/gin"
// 3. 本项目其他包(用 module 名 + 子路径)
"myproject/internal/service"
)通常按这三类分组写,每组之间用空行分隔。
gofmt会自动排序。
2.3 init 函数
每个文件可以定义 func init(),在被导入时自动执行一次。
go
package config
var DB *sql.DB
func init() {
DB, _ = sql.Open("mysql", "...")
}执行顺序:被依赖的包 → 当前包,按导入路径深度优先。
🚀 3. Go Module:依赖管理革命
3.1 GOPATH 时代的痛
Go 1.10 之前,所有项目必须放在 $GOPATH/src/ 下,依赖统一放 $GOPATH/pkg/,不支持版本管理。
如果项目 A 用 lib v1,项目 B 用 lib v2,怎么办?只能…痛苦地共存或冲突。
3.2 Module 时代
Go 1.11 引入 Go Module,每个项目独立管理依赖,类似:
- Java 的 Maven
- Node.js 的 npm/package.json
- Rust 的 Cargo
- Python 的 requirements.txt(更接近 Cargo)
3.3 创建一个 Module
bash
mkdir myapp && cd myapp
go mod init github.com/yourname/myapp会生成 go.mod:
module github.com/yourname/myapp
go 1.21
module名 = 你这个项目对外的"包路径",通常用代码仓库地址。
3.4 添加依赖
bash
go get github.com/gin-gonic/gin
go get github.com/gin-gonic/gin@v1.9.1 # 指定版本
go get github.com/gin-gonic/gin@latest # 最新go.mod 会自动更新:
require (
github.com/gin-gonic/gin v1.9.1
)同时生成 go.sum,记录依赖的哈希值,防止依赖被恶意篡改。
3.5 移除未用依赖
bash
go mod tidy会自动:
- 添加代码里 import 但 go.mod 没有的依赖
- 删除 go.mod 里有但代码没用的依赖
提交代码前记得跑一次
go mod tidy,保持干净。
📋 4. go.mod 文件解析
module github.com/yourname/myapp
go 1.21
require (
github.com/gin-gonic/gin v1.9.1
github.com/spf13/viper v1.18.2
)
require (
// 间接依赖(被 require 的依赖再依赖的库)
github.com/spf13/cobra v1.8.0 // indirect
)
replace (
// 用本地路径或 fork 的版本替换
github.com/old/lib => github.com/new/lib v1.0.0
github.com/somelib => ../local-fork/somelib
)
exclude (
// 排除某个版本
github.com/bad/lib v1.0.0
)4.1 go.sum 文件
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3v0pYJDk=每个依赖记录两行:源码哈希 + go.mod 哈希。永远要把 go.sum 提交到 Git。
📂 5. 标准项目布局
社区惯例(golang-standards/project-layout):
myapp/
├── cmd/ # 主程序入口
│ └── server/
│ └── main.go
├── internal/ # 内部代码(外部不能 import)
│ ├── service/
│ ├── repository/
│ └── handler/
├── pkg/ # 可被外部 import 的库
│ └── utils/
├── api/ # API 定义(OpenAPI、proto)
├── configs/ # 配置文件
├── scripts/ # 脚本
├── test/ # 测试数据
├── go.mod
├── go.sum
├── Makefile
└── README.md
internal/是 Go 编译器特殊处理的目录:放在里面的包只能被父目录及其子目录的代码 import,外部项目无法引用。这是 Go 内置的"私有包"机制。
🛠 6. 常用 go 命令
| 命令 | 作用 |
|---|---|
go mod init <name> | 初始化 module |
go mod tidy | 整理依赖 |
go mod download | 下载所有依赖到本地缓存 |
go mod vendor | 把依赖拷到 vendor/ 目录 |
go mod graph | 显示依赖关系图 |
go mod why <pkg> | 解释为什么需要这个依赖 |
go list -m all | 列出所有依赖 |
go list -m -u all | 列出可升级的依赖 |
go get -u | 升级所有依赖 |
go get pkg@version | 切换到指定版本 |
🌐 7. 国内镜像加速
国内访问 proxy.golang.org 慢,配置代理:
bash
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
# 私有仓库不走代理
go env -w GOPRIVATE=*.mycompany.com,github.com/myorg/*🧠 8. 语义化版本(SemVer)
Go Module 严格要求 v主版本.次版本.补丁:
| 升级 | 含义 | 示例 |
|---|---|---|
| 主版本 | 不兼容变更 | v1.x → v2.0.0 |
| 次版本 | 兼容的新功能 | v1.0 → v1.1 |
| 补丁 | 兼容的 bug 修复 | v1.0.0 → v1.0.1 |
大版本号 ≥ 2 时,import 路径需带版本号:
goimport "github.com/some/lib/v2" // v2.x 必须这样
📚 本章小结
| 概念 | 一句话总结 |
|---|---|
| package | 同一目录下文件的逻辑分组 |
| import | 引入其他包 |
| 大写/小写 | 决定标识符是否对外暴露 |
| go.mod | 依赖清单 |
| go.sum | 依赖哈希校验 |
| go mod tidy | 整理依赖 |
| internal/ | 私有包目录 |
📁 本章配套
- 📄 examples/:包结构与 module 实战
- 🌐 demo.html:依赖管理可视化
- ❓ interview.md:高频面试题
- 🖼 diagrams/:图解 module 工作流
进入第11章 →