写了一个好用的 Go 包,想分享给别人?本文带你从零了解 Go 模块的创建、发布和引用方式。
在 Go 中有两个容易混淆的概念:模块(Module) 和 包(Package)。
| 概念 | 定义位置 | 作用 |
|---|---|---|
| 模块 (Module) | go.mod 中的 module xxx | 整个项目的唯一标识,导入路径的起点 |
| 包 (Package) | .go 文件顶部的 package xxx | 代码组织单元,一个模块可以包含多个包 |
简单理解:模块是小区名,包是楼号。别人找你的代码,先找小区(模块),再找楼(包)。
gotest/
├── go.mod # 模块定义
├── main.go # 主程序(可选)
└── mathutil/ # 一个可被外部使用的包
└── mathutil.go
module gotest go 1.26.1
module gotest 声明了模块名。模块名是所有包导入路径的前缀。
mathutil/mathutil.go:
package mathutil
// Add 返回两个整数的和
func Add(a, b int) int {
return a + b
}
main.go:
package main
import (
"fmt"
"gotest/mathutil" // 模块名/包名
)
func main() {
result := mathutil.Add(10, 20)
fmt.Println("10 + 20 =", result) // 输出: 10 + 20 = 30
}
导入路径的规则:模块名 + "/" + 包的目录路径。
这是 Go 社区的标准做法。Go 的模块名天然就是一个网络地址。
将 go.mod 中的模块名改为你的 GitHub 仓库路径:
module github.com/yourname/gotest go 1.26.1
同时更新所有 import 路径:
import "github.com/yourname/gotest/mathutil"
git init git add . git commit -m "初始提交" git remote add origin https://github.com/yourname/gotest.git git push -u origin main # 打上版本标签(推荐语义化版本) git tag v1.0.0 git push --tags
别人只需要两步:
# 1. 下载你的包 go get github.com/yourname/gotest/mathutil
// 2. 在代码中导入
package main
import (
"fmt"
"github.com/yourname/gotest/mathutil"
)
func main() {
fmt.Println(mathutil.Add(3, 5)) // 输出: 8
}
Go 会根据模块名自动从 GitHub 下载代码。这就是为什么 Go 社区约定用 github.com/xxx 作为模块名 —— 导入路径和下载地址合二为一。
如果只是把源码拷给朋友,不想发到网上,可以用 replace 指令。
workspace/
├── gotest/ # 你分享的源码
│ ├── go.mod
│ └── mathutil/
│ └── mathutil.go
└── friend-project/ # 朋友自己的项目
├── go.mod
└── main.go
module friend-project go 1.26.1 require gotest v0.0.0 // 关键:用 replace 将模块名映射到本地路径 replace gotest => ../gotest
replace 告诉 Go:"别去网上找 gotest 这个模块了,它就在旁边的文件夹里。"
package main
import (
"fmt"
"gotest/mathutil"
)
func main() {
fmt.Println(mathutil.Add(3, 5)) // 输出: 8
}
| GitHub 发布 | 本地 replace | |
|---|---|---|
| 适合场景 | 开源项目、团队协作 | 私下分享、离线使用 |
| 别人如何获取 | go get github.com/xxx | 手动拷贝源码 |
| 版本管理 | Git Tag(v1.0.0) | 无版本管理 |
| 是否需要网络 | 首次下载需要 | 不需要 |
| 推荐程度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
不是必须的。模块名可以是任意字符串(比如 gotest、myapp)。但如果你要发布到网上让别人用,就需要用真实的仓库地址(如 github.com/yourname/gotest),这样 go get 才知道去哪里下载。
可以。Go 的导入粒度是包级别的。别人可以只导入 github.com/yourname/gotest/mathutil,不需要导入整个模块。
go mod init 创建模块go get 就能用replace 指向本地路径Go 的模块系统设计哲学:导入路径即下载地址。