Skip to content

3.1 Go mod 模块管理

实际开发中经常需要复用他人代码(HTTP 框架、驱动等),也会把自己的通用功能发布成模块给别人用。Go Modules(口语常称 Go mod)是官方推荐的依赖管理方式:用 go.mod / go.sum 声明与校验依赖,版本可复现,项目不必再绑死在 $GOPATH/src 下。

建议先建立本章的模块心智,再读 3.2 包与导入,掌握 import 写法、别名、空白导入、init 顺序等;两节一起构成日常写 Go 的依赖与导入基础。

一、为什么需要模块管理

1. 早期痛点与 Go Modules

在 Go 1.11 之前,长期依赖 GOPATH:源码放在 $GOPATH/src同一依赖在本地往往只能保留一个版本,多项目协作困难;vendor(约 1.5 起)把依赖拷进项目,缓解多版本问题,但维护与分享仍不够统一。

Go 1.11 引入 Go ModulesGo 1.14 起官方明确推荐在生产中使用。如今在有 go.mod 的项目上默认走模块模式,Go mod 应作为默认工作方式

2. 模块管理带来的能力

  • 代码复用:按模块路径引用远程或本地库,版本明确。
  • 版本与校验go.mod 约束版本,go.sum 记录校验和,减少环境漂移。
  • 依赖隔离:不同项目可使用同一依赖的不同版本(模块缓存与各自 go.mod 区分)。
  • 工程位置灵活:项目可放在任意目录,根目录有 go.mod 即可。
  • 工具链维护go getgo mod tidy 等自动维护依赖声明。

二、模块与包的基本概念

1. 模块是什么

模块(Module) 是包含若干 Go 包 的代码单元,由根目录的 go.mod 划定边界。模块有唯一的 模块路径(通常与仓库 URL 一致,如 github.com/gin-gonic/gin),通过路径 + 版本被引用。

2. 模块与包的关系

概念含义
包(Package)同一目录下多个 .go 文件,共用一条 package 声明。
模块(Module)一个或多个包,由 go.mod 管理,对应一个模块路径。

一个模块包含多个包;一个包只属于一个模块。 导入路径一般为 模块路径 + 子目录(标准库除外)。

3. 标识符可见性(导出/未导出)

跨包访问时,首字母大小写决定能否被外部使用:

  • 大写开头导出,其他包可引用。
  • 小写开头未导出,仅本包内可用。
go
package mathutil

func Add(a, b int) int { return a + b }   // 导出
func mul(a, b int) int { return a * b } // 未导出

结构体字段同理。import 的各种写法、init、空白导入3.2 包与导入

4. internal 目录

路径中含 internal 的包,只能被位于该 internal 父目录树内的包导入,用于隐藏模块内部实现。

5. 与下一节的分工

  • 3.1(本章):模块初始化、go.mod / go.sum、代理、版本、私有库、vendor
  • 3.2:包与导入路径、import 语法、别名、点导入、匿名导入、init 与解析顺序。

三、初始化模块:go mod init

bash
go mod init <模块路>

示例:

bash
mkdir myapp && cd myapp
go mod init github.com/yourusername/myapp

生成 go.mod 大致如下:

go
module github.com/yourusername/myapp

go 1.22

模块路径宜与将来托管地址一致;私有库可用公司域名前缀。若已有 go.mod,勿重复 init;改路径可用 go mod edit 或手改后 go mod tidy

四、代理与镜像:GOPROXY

bash
go env GOPROXY

国内常用(写入用户配置):

bash
go env -w GOPROXY=https://goproxy.cn,direct

direct 表示代理未命中时尝试直连源站。团队与 CI 建议统一代理配置。

五、依赖的日常操作

1. 添加依赖

代码中 import 第三方路径 后执行 go build / go run / go test,会拉取依赖并更新 go.modgo.sum。也可:

bash
go get github.com/gin-gonic/gin@latest
go get github.com/gin-gonic/gin@v1.9.0

2. 更新与整理

bash
go get -u ./...
go get -u=patch github.com/gin-gonic/gin
go mod tidy

go mod tidy 会删除未使用依赖、补全缺失项;不要只手删 require 行就当清理完成。

3. 查看与校验

bash
go mod graph
go list -m all
go mod why -m golang.org/x/net
go mod download
go mod verify

六、go.modgo.sum

1. go.mod 常见指令

指令作用
module模块路径
go语言版本(最低兼容)
require依赖及版本
replace替换模块路径(本地调试等)
exclude排除某版本

2. go.sum

记录依赖内容的 校验和,防篡改。应与 go.mod 一并提交;勿手改,由工具维护。

七、版本与语义化版本

语义化版本 v主.次.补丁:主版本不兼容变更;次版本兼容增功能;补丁兼容修 bug。v2+ 常需在模块路径上加 /v2 等约定。

bash
go get github.com/gin-gonic/gin@latest
go get github.com/gin-gonic/gin@v1.9.1

未打标签的提交可能出现 伪版本(时间戳 + 提交哈希)。

八、私有模块与 replace

bash
go env -w GOPRIVATE=git.company.com,github.com/myorg/*

仍需本机 Git 能访问私有仓库。本地联调可在 go.mod 中:

go
replace git.company.com/utils => ../utils

上线前去掉或改为正式版本。

九、直接依赖与 // indirect

直接依赖:你的代码 import 的模块。间接依赖:被上述模块再引入的模块。// indirect 由工具维护,go mod tidy 会整理。

十、vendor 目录

bash
go mod vendor
go build -mod=vendor

适用于离线构建、审计、CI 固定快照等;是否提交 vendor 由团队约定。

十一、常用命令速查

命令作用
go mod init初始化模块
go get添加/升级依赖
go mod tidy整理依赖
go mod download下载到缓存
go mod vendor生成 vendor
go mod graph依赖图
go mod verify校验缓存
go list -m all列出模块版本

十二、常见问题

拉取失败:查 GOPROXY、网络、GOPRIVATE、Git 权限。

版本冲突go mod graph / go mod why 定位后 go get 指定版本 或升级主版本(可能改 import 路径)。

与 CI 不一致:统一 Go 版本,提交 go.mod / go.sum

十三、实践练习

  1. mkdir go-mod-demo && cd go-mod-demo,执行 go mod init example.com/go-mod-demo

  2. main.go

    go
    package main
    
    import (
    	"fmt"
    
    	"github.com/google/uuid"
    )
    
    func main() {
    	fmt.Println(uuid.New().String())
    }

    执行 go run .,观察下载依赖;再 go mod graphgo mod tidy

  3. (可选)引入 gin,提供 GET /api/v1/uuid 返回 JSON,再 go mod tidy 并访问 http://localhost:8080/api/v1/uuid

十四、小结

Go modgo.mod + go.sum 为核心,配合 GOPROXYGOPRIVATEgo get / go mod tidy 形成可复现依赖流。细节以当前版本的 go help modules 为准。下一步阅读 3.2 包与导入,把 import 与包初始化写扎实。