首先以一段 hello world 来说明Go 模块化管理的相关知识
package main
import "fmt"
func main(){
fmt.Println("hello,world")
}
包
package main
说明当前这个 .go
文件归属于 main 包,
任何 .go 文件的第一行都是 package xxx
包是 Go 语言中的基本组成单位,通常使用小写方式来命名,每一个程序都是由若干个 Go 包的集合。
导包
import "fmt"
这里 “fmt” 指的是包的导入路径,表示的是标准库下的 fmt 目录,而 整个 import 语句的含义是导入标准库 fmt 目录下的包。
导入包应该是 modulepath + “目录”
fmt.Println("hello,world")
这里的 “fmt” 指的是包名
module
Go 源码需要先编译,再分发和运行。
如果是单 Go 源文件的情况,我们可以直接使用 go build 命令 +Go 源文件名的方式编译。
对于复杂的 Go 项目,我们需要在 Go Module 的帮助下完成项目的构建。
一个 module 就是一个包的集合,这些包和 module 一起打版本、发布和分发。
go module 的核心就是 go.mod 文件,其中存储了这个 module 对第三方依赖的全部信息。
解析与相关命令请看: https://encore.dev/guide/go.mod
module path
module “xx module pathxx”
第一行内容是用于声明 module 路径(module path)的。而且,module 隐含了一个命名空间的概念,module 下每个包的导入路径都是由 module path 和包所在子目录的名字结合在一起构成。
如果想导入本地的其他的包,需要 import modulepath + “该包所在的子目录”
go mod init + “xx module path xx” go mod init命令的实际行为就是在当前目录下创建一个go.mod,而这个go.mod将当前目录转换为一个go module。
这个 module path 可以是任意的,不需要和文件系统相对应,建议和项目目录相同。
go module 是一个逻辑上的概念,与文件夹名称无关,有了 go.mod 后,这个文件夹下的各个包就算是这个go module下面的包了。包的导入路径也是以module path为前缀的。
go mod tidy下载的第三方包一般在$GOPATH/pkg/mod下面。如果没有设置GOPATH环境变量,其默认值为你的home路径下的go文件夹。这样第三方包就在go文件夹的pkg/mod下面。
包依赖问题
全面使用 go mod 模式
1. 创建 go mod init +${module path} 创建 go.mod 文件,将当前项目变为一个 Go Module
2. go mod tidy 更新依赖 , 由 go mod tidy 下载的依赖 module 会被放置在本地的 module 缓存路径下,默认值为 $GOPATH[0]/pkg/mod,Go 1.15 及以后版本可以通过 GOMODCACHE 环境变量,自定义本地 module 的缓存路径。
3. go build 执行新 module 的构建,go build 命令会读取 go.mod 中的依赖及版本信息,并在本地 module 缓存路径下找到对应版本的依赖 module,执行编译和链接。如果顺利的话,我们会在当前目录下看到一个新生成的可执行文件
版本选择
Q:项目所依赖的包有很多版本,Go Module 是如何选出最适合的那个版本的呢?
语义导入版本 :
1. 主版本号不同的两个版本是相互不兼容的。
2. 在主版本号相同的情况下,次版本号大都是向后兼容次版本号小的版本。补丁版本号也不影响兼容性。
如果一个包的新旧版本都是兼容的,那么它们的包的导入路径是相同的。
如果要引入同一个包的,两个不同主版本号,那么就需要将包主版本号引入到包导入路径中。
最小版本选择原则:就是选择满足的最小的版本