Golang环境——GOPATH vs go.mod

发布时间 2023-05-28 11:38:18作者: 晓风晓浪

GOPATH在本文中,我们将探讨 Go 编程的传统环境与基础环境之间的差异go.mod

这种区别对 Go 开发人员如何构建和管理他们的项目工作区和依赖项具有重要意义。

我们将从了解GOPATH环境、它的组织和结构开始。然后,我们将探讨go.mod采用这种方法来提供模块化和灵活的方式来组织 Go 项目。

GOPATH了解这两种环境以及从到 的过渡go.mod为 Go 不断发展的生态系统提供了宝贵的见解。

https://www.java567.com,搜"go")

单一工作区——GOPATH 环境变量

Go 编程语言最初为文件系统内的依赖项和自定义项目的位置划定了一个范围。这是由GOPATH环境变量定义的。这意味着 Go 只会在该变量指向的目录下查找二进制文件和源代码。

默认情况下,该GOPATH变量将指向/go直接在用户主目录路径下定义的文件夹(~/在基于 unix 或%HOMEPATH%基于 windows 的系统中)。

GOPATH``GOPATH也可以设置为自定义路径,并且可以为单个用户定义多个路径(但由于依赖管理增加了困难,因此不鼓励这样做)。

GOPATH在、srcpkg下有三个值得注意的目录bin。该src目录包含项目和已安装依赖项的源代码。当您执行诸如 之类的命令时go get github.com/user/repo,Go 工具会从指定位置获取模块并将其放入src下的目录中GOPATH,路径以资源的 URL 命名。

例如,如果您要从 GitHub 上“someuser”拥有的存储库下载一个库,则该库的源代码将驻留在/home/user/go/src/github.com/someuser/library.

pkg目录包含您的代码所依赖的已编译包对象(.a 文件)。构建包时,生成的文件放在pkg目录中。编译后的包文件有助于减少编译时间,因为它们可以直接导入其他包而无需重新编译。

bin目录包含应用程序的二进制可执行文件。当您构建可执行程序时,生成的二进制文件将放在该bin目录中。

GOPATH 工作区的文件树

这假定默认路径为GOPATH

 /home/user/go/         <--- This is your GOPATH
 ├── bin/
 ├── pkg/
 │   └── linux_amd64/
 │       └── github.com/
 │           └── someuser/
 │               └── somelib.a   <--- Compiled dependency package
 └── src/
    ├── github.com/
    │   └── someuser/
    │       └── somelib/         <--- Dependency's source code
    │           └── somelib.go
    └── myapp/                   <--- Your project
        └── main.go

在这个结构中:

  • src 目录包含项目的源代码和已安装的依赖项。

  • pkg 目录包含您的代码所依赖的包的编译版本。

  • bin 目录包含已编译的二进制可执行文件。

定义的单一工作区结构GOPATH意味着你所有的 Go 代码及其依赖项共享一个公共空间。

然而,值得注意的是,这种方法随着 Go 1.11 中 Go 模块的引入而发展。这主要解决了缺乏适当的依赖关系版本控制系统和在文件系统下存储项目的灵活性。

模块化方法——go.mod文件

从 Go 1.11(2018 年 8 月)开始,模块化选项可作为GOPATH. 这是由文件的存在分隔的go.mod,通常还有一个 go.sum 文件,一旦执行任何与外部托管包有关的操作(如go get <package>),就会生成该文件。

然而,在继续之前,重要的是要弄清楚包是什么以及模块与包的区别:

Go 中的包

Go 中的包是代码分发的最小单位。它们由一个目录定义,该目录包含一个或多个.go源文件,并在其顶部声明了包名称。目录中的所有文件必须声明相同的包名称。

包允许组织和重用代码。它们提供了一种将相关代码封装到一个单元中的方法,该单元可以被其他包导入和使用。例如,Go 标准库由许多包组成,例如 fmt、os、net 等。

有一个特殊的包名,main. 该包包含main()作为项目入口点的函数。每个最终要成为可执行文件的项目都必须包含函数main(),因此也main包含包。

最好在项目的根文件夹中声明主包文件,在自己的目录中声明其他包。

Go 中的模块

模块是相关的 Go 包的集合,它们作为一个单元一起进行版本控制。模块记录精确的依赖需求并创建可重现的构建。

Go 模块由位于模块目录层次结构根目录下的 go.mod 文件定义。该文件定义了模块路径,即模块内所有包的导入路径前缀。它指定了模块的依赖关系,包括其他模块所需的版本。

模块允许版本控制和一起发布一组包,它们还使依赖版本信息明确且更易于管理。请注意,尽管已进行版本控制,但默认情况下**仍会src在范围内定义的GOPATH**范围内下载依赖项。

总而言之,虽然包是一种在 Go 程序中构建和重用代码的方式,但模块是包的版本化集合,它还处理依赖管理。这允许每个 Go 项目都有自己的隔离和可重现的构建环境。

模块的命名约定

在 Go 中,模块名称在系统范围内使用,因此应该尽可能具体,特别是如果您计划将模块分发给其他开发人员。模块名称在文件中指定go.mod,该文件充当模块的清单,位于模块目录层次结构的根部。

以下是 Go 中模块命名的一些准则:

模块路径:模块路径应该是模块的全局唯一标识符。它通常采用倒序的 Internet 域名形式,后跟模块名称。例如,github.com/littlejohnny65/example-module。从模块导入包时,模块路径用作导入路径。

模块名称:模块名称是模块路径的最后一个组成部分。它应该简短、具有描述性,并遵守 Go 的命名约定。建议使用不带下划线或混合大写的小写字母。例如,examplemodule

版本控制:模块名称本身不包含版本信息。模块的版本在go.mod文件中使用模块版本标识符单独指定,例如v1.2.3. 模块路径和版本标识符的组合唯一标识模块的特定版本。

为模块选择有意义和描述性的名称很重要,因为它们是公开可识别的,并且可以在其他项目中用作依赖项。清晰一致的命名约定有助于理解模块的用途和上下文。

go.sum 文件

当您运行类似 的命令时go get github.com/user/repo,Go 工具将从该位置获取模块。这使得在任何支持版本控制系统(如 Git、Mercurial、Bazaar 或 Subversion)的服务器上托管 Go 代码成为可能。

Go 有一种非常灵活和直接的方法来从外部存储库下载依赖项。所以为了保证依赖的完整性所采用的解决方案是创建一个本地文件来存储每个依赖的校验和。这是保证安装的依赖项完全相同的原因。

校验和文件由本地 Go 工具生成。如果您想确保依赖项与本地环境中的依赖项完全相同,则应将其推送到服务器和 Dockerfiles 等外部环境。

模块化 Go 项目的文件树

 /home/user/projects/
 └── myapp/                         # Your project
    ├── custom/                   # Custom packages
        └── ...                         # .go files defining functionality
    ├── go.mod                     # go.mod file defining dependencies & versions
    ├── go.sum                     # go.sum file that verifies dependency integrity
    └── main.go                   # Entrypoint

模块缓存的文件树,假定默认的 GOPATH 路径:

 /home/user/go/        # This is your GOPATH
 └── pkg/
    └── mod/
        └── cache/
            └── download/
                └── github.com/
                    └── someuser/
                        └── somelib/     # Source code of the dependency
                            └── somelib.go

在这个结构中:

  • 您的项目可以存在于文件系统中的任何位置。它包含一个 go.mod 文件和一个 go.sum 文件。

  • go.mod 文件列出了您的项目使用的依赖项的特定版本。

  • go.sum 文件在将每个依赖项添加到模块时提供其确切内容的校验和。

  • 依赖项存储在 Go 模块缓存中,它在系统上的所有项目之间共享。

模块 CLI 命令

有几个方便的命令可用于处理模块化 Go 项目:

go mod init: 在当前目录中初始化一个新模块。它创建一个go.mod定义模块路径的文件并将其设置为依赖管理。

go mod tidy:从文件中添加缺失和删除未使用的模块和依赖项go.mod。它确保go.mod文件准确反映项目所需的依赖项。

go mod download:下载文件中定义的依赖项go.mod,并将它们存储在模块缓存中。它获取项目所需的特定版本的依赖项。

go mod vendor:将依赖项复制到vendor项目中的目录中。当您想要创建一个包含其所有依赖项的独立项目时,此命令很有用。

go mod verify:验证模块缓存中的依赖项是否与go.sum文件中指定的预期加密校验和匹配。它确保下载的依赖项的完整性和真实性。

go mod graph:打印模块依赖图,显示模块及其版本之间的关系。它对于理解项目依赖项的整体结构很有用。

go mod edit:提供一系列用于对文件进行手动编辑的子命令go.mod。它允许您添加、删除或更新模块要求、替换模块等。

这些只是一些常用的go mod命令。go help mod您可以通过运行或参考关于模块的官方 Go 文档来探索更多命令及其选项。

包起来

模块化方法与单一工作区并无根本区别或不兼容。但它建立在它的基础上,以带来更多的灵活性和可管理性。

模块允许您在文件系统中的任何地方拥有一个项目,并且还具有命名空间依赖性以获得更好的稳定性。但它仍然使用 GOPATH 作为默认位置来存储依赖项和可执行文件。

总之,go.mod 提供的模块化环境是 Go 开发者工具箱中的一个强大工具,补充和扩展了传统 GOPATH 环境的功能。它标志着 Go 适应了现代软件开发的复杂性和规模不断增加,展示了该语言为满足其用户不断变化的需求而不断发展。

随着我们的前进,想象一下 Go 生态系统的未来发展将会令人兴奋。

https://www.java567.com,搜"go")