跳到主要内容

go模块

 模块是 go 代码包的集合,模块根目录下的 go.mod 文件定义了模块的路径、依赖等信息。

module hello-world

go 1.17

require (
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
rsc.io/quote/v4 v4.0.1 // indirect
rsc.io/sampler v1.3.0 // indirect
)

1. 创建新的模块

 在golang开发环境搭建一文中,介绍了如何创建一个新的模块,这里就不再赘述了。

2. 添加依赖

 在 golang 开发过程中,需要用到其他人开发的模块。像 MavenNPM 这些包管理工具,都有中心仓库,开发者开发好软件包之后,提交到中心仓库,其他人就可以使用了。

golang 的包管理思路不同于以上,golang 采用半中心化的思路。任意的git仓库都可以作为 golang 的包仓库,只要仔细观察你就会发现不同的包会来自不同的地址(这点和 MavenNPM 非常不同)。

By default, the go command may download modules from https://proxy.golang.org. It may authenticate modules using the checksum database at https://sum.golang.org. Both services are operated by the Go team at Google.The privacy policies for these services are available at https://proxy.golang.org/privacy and https://sum.golang.org/privacy, respectively.

The go command's download behavior may be configured using GOPROXY, GOSUMDB,GOPRIVATE, and other environment variables

 当执行 go get 命令的时候,golang 首先检查本地是否有需要安装的包,如果没有找到,就会去服务器下载。下载地址取决于 GOPROXY 这个变量值,GOPROXY 默认值为:https://proxy.golang.org, direct。这个默认值的含义是,如果在 https://proxy.golang.org 没有找到需要安装的包,就去包名对应 URL 下载。

proxy.golang.org 是由 google 运营的模块镜像仓库,它会从源服务器同步模块到 proxy.golang.org ,当用户安装时,优先从 proxy.golang.org 下载。

警告

中国大陆屏蔽了 proxy.golang.org ,只能使用其他的镜像仓库,例如:goproxy.cn。使用的时候,修改 GOPROXY 的值即可。

$ go env -w GO111MODULE=on
$ go env -w GOPROXY=https://goproxy.cn,direct

 接下来,看看执行 go get rsc.io/quote/v4 后,发生了什么。

  1. go.mod 文件里面多了 require 的内容。
  2. 多了文件 go.sum

require 比较好理解,在执行 go get 的时候,将包的依赖加到 go.mod 中。go.sum 文件的每一行数据包括包名、包版本和对应的 hash 值,它用来保证之后下载的包与第一次下载的包一致,防止包被恶意篡改。

 在代码里面引入 quote,成功调用 quota.Hello() 方法。

提示

 如果无法下载 quote 包,清参考golang环境搭建里面的代理设置。

3. 升级包依赖

golang 的包版本号的格式类似于 v0.1.2,其中 0 是大版本号,1 是小版本号,2 为补丁。执行 go list -m all 时,发现 golang.org/x/text 使用的是没有 tag 的版本,需要升级到最新的 tag 版本。你会发现 go.mod 里,require 部分相应的发生了变化,同时 go.sum 里新增了最新版的记录。

go get golang.org/x/text

 细心的小伙伴可能发现,包后面有 indirect 的标注,这个 indirect 表示不直接依赖这个包。例如 AB, BC,那么 A 就间接依赖 C。但是上述代码里面直接引用了 quote 包,为什么它也是 indirect?这可能是先 go get,后在代码里面引用的缘故,执行 go mod tidy 即可。

4. 发布包

go 支持用户发布自己开发的模块。前面提到,Go Proxy 并不是一个中心化的仓库,它会同步用户发布的模块,所以需要用户先将模块发布到互联网上。最方便的发布方式是使用 github。不清楚如何使用 github 的可以参考github使用指南

4.1 新建代码仓库

 在 github 上创建一个空的仓库,将空仓库拉到本地。

4.2 编写包代码

 新建模块,其中 linlan-doc 是你的账号名,golang-repo 是你的仓库名

go mod init github.com/linlan-doc/golang-repo

 创建文件夹 str,在 str 文件夹下创建 hello.go 文件,代码如下,这段代码引用了前面的 quote,在它的 Hello 方法返回结果后面加上 lin 返回给调用者。

package str

import (
"rsc.io/quote"
)

func LinHello() string {
return quote.Hello() + "lin"
}

 提交代码并打上 v0.1.0tag,将 tag 推送到 github

git commit -m "mymodule: changes for v0.1.0"
git tag v0.1.0
git push origin v0.1.0

 将模块同步到Go Proxy。提示成功后,即可在pkg.go.dev搜索到。

go list -m github.com/linlan-doc/golang-repo

4.3 使用包

 新建一个项目,引用刚发布的模块。在新项目下新建一个 main 文件夹,在 main 文件夹下新建 test.go 文件,调用模块里面的 LinHello 方法,观察控制台的输出结果。

警告

 需要新建项目,在打包项目直接引用会报错。

test.go
package test

import (
"fmt"

repo "github.com/linlan-doc/golang-repo/str"
)

func main() {
fmt.Println(repo.LinHello())
}
go.mod
module test

go 1.17

require github.com/linlan-doc/golang-repo v0.1.0

require (
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
rsc.io/quote v1.5.2 // indirect
rsc.io/sampler v1.3.0 // indirect
)
提示

 根据 go 语言的标准,程序的入口是 main 包下的 main 方法

5. 包与目录的关系

 上述例子里,模块、包、目录的关系非常混乱,本小节进行说明。

  1. 发布的模块名为:github.com/linlan-doc/golang-repo,所以在 go.mod 文件里面 require 的模块名为 github.com/linlan-doc/golang-repo
  2. 发布的模块里 str 包在目录 str 下,所以 import 的路径为 github.com/linlan-doc/golang-repo/str,即告诉 go 编译器,str 包在 str 目录下,代码里给 str 包重新命名为 repo
  3. 通过包名调用对应方法。
警告
  1. 同一个目录下,不能申明两个包,否则编译器会报错。
  2. 包名和目录名不需要一致,但建议保持一致,减少不必要的理解成本。
  3. 同一个包下,直接用方法名进行调用。

署名-非商业性使用-禁止演绎 4.0 国际