11. 包和模块
在第 9 章中介绍结构体及其内部的字段的可见性时介绍到 Go 语言中包的概念。前面章节的例子,绝大部分都只是一个 main.go 文件就可以了,这对于一个简单的程序已经够了。但是,随着项目越来越大,代码也会越来越多,所有代码都放在一个目录、一个包中,会出现很多问题,如文件越来越多,难以维护;不同功能的代码混杂在一起,可读性差等等。为了解决这些问题,Go 引入了两个十分重要的概念:
- Package(包):用于组织代码。
- Module(模块):用于组织项目和管理依赖。
二者虽然都可以理解为“组织代码”,但职责完全不同。可以简单理解为:Package 是代码组织单位,而 Module 是项目管理单位。本章将详细介绍二者的设计思想、使用方法以及它们之间的关系。
11.1. Package
11.1.1. 什么是 Package
Package(包)是 Go 中最基本的代码组织单位。可以把一个 Package 理解成一组完成同一类功能的 Go 源文件,如前面章节中我们大量使用的 Go 标准库中的 fmt 包,该包的主要功能就是格式化输入输出,每个 Package 都负责一类功能。除了 fmt 包,在 Go 标准库中还有大量其他的包,如:
strings:字符串处理math:数学计算os:操作系统相关- …
这些标准库中的包,我们在使用的时候使用 import 导入,代码如下:
import "fmt"
当有多个包需要导入时,可以用如下的方式:
import (
"fmt"
"strings"
)
11.1.2. 构建自己的代码
我们还是构建一个 animal 的项目,目录结构如下:
├── animal
│ ├── cat
│ │ ├── cat.go
│ ├── dog
│ │ ├── dog.go
├── main.go
在 Go 语言中,一个文件夹就是一个 package,因此在 cat.go 文件中写下如下代码:
package cat
import "fmt"
func Meow() {
fmt.Println("Cat Meow")
}
在 dog.go 文件中写下如下代码:
package dog
import "fmt"
func Bark() {
fmt.Println("Dog Bark")
}
这样就构建好了两个文件,现在在 main.go 文件中引用这两个文件,代码如下:
package main
import (
"animal/cat/cat"
"animal/dog/dog"
)
func main() {
dog.Bark()
cat.Meow()
}
此处的 import 我们暂且按照相对路径导入。以 "animal/cat/cat" 为例,其中,animal 为目录,第一个 cat 也是文件夹名,最后的 cat 为 package 名。
此时,我们运行 go run main.go 发现报错:“package animal/cat is not in std (/usr/local/go/src/animal/cat) ”和“package animal/dog is not in std (/usr/local/go/src/animal/dog)”。这说明 Go 没有找到 animal/cat 和 animal/dog 这两个包,而是把它们当成了标准库(stdlib)来查找。这个时候就需要使用到 Modules 的概念。
11.2. Module
Package 解决的是代码组织的问题。那么,一个项目越来越大之后,还会遇到新的问题,如如何管理第三方库;如何记录依赖版本等等。于是 Go 引入了 Module。Module 可以理解成一个完整的 Go 项目。
每个 Module 的根目录通常都会存在一个 go.mod 文件。对于一个新的项目,可以在当前空的项目文件夹下用如下的命令创建项目:
go mod init xxx
这样就可以创建一个新的项目,注意,这里的 xxx 称为模块路径,同时在项目下出现文件 go.mod,文件内容如下:
module xxx
go 1.26.1
对于我们上述的项目,在根目录下新建 go.mod 文件,并设置内容为:
module animal
go 1.26.1
此时,相当于模块路径为 animal,我们修改 main.go 文件中的 import 语法,如下:
package main
import (
"animal/animal/cat"
"animal/animal/dog"
)
func main() {
dog.Bark()
cat.Meow()
}
此时,再运行代码发现程序已经能正常运行了。我们发现在原先的相对路径前增加了模块名称,这也就对应着 import 中的语法,具体为:import 路径 = module 名称 + package 所在目录。
11.3. 本章小结
随着项目越来越大,代码也会越来越多,所有代码都放在一个目录、一个包中,会出现很多问题,为此,在 Go 语言中引入了 Package 和 Module 这两个概念,其中,Package(包)是 Go 中最基本的代码组织单位,主要解决的是代码组织的问题。而 Module 主要解决的是项目的管理问题,如管理第三方库,记录依赖版本等等,Package 和 Module 这两个概念称为开发大型项目的标配。