Golang环境:Gopath vs Go.mod
#go #modules #gomodules #gopath

介绍

在本文中,我们深入研究了传统的GOPATH环境与基于go.mod的GO编程环境之间的对比,以及它们的相似性和差异。这种区别对GO开发人员如何构建和管理其项目工作空间和依赖性具有重要意义。

我们首先了解GOPATH环境,其组织及其结构。然后,我们探索go.mod方法,该方法采用了一种模块化,灵活的组织GO项目的方式。了解这两个环境以及从GOPATHgo.mod的过渡提供了对Go的不断发展的生态系统的宝贵见解。

单个工作区:Gopath环境变量

GO编程语言最初是针对由GOPATH环境变量定义的文件系统中依赖项和自定义项目位置的范围的。这意味着GO仅在此变量指向的目录下寻找二进制文件和源代码。

默认情况下,GOPATH变量将指向直接在用户主目录路径下定义的/go文件夹(基于unix的~/或基于Windows的系统上的~/)。GOPATH也可以设置为自定义路径,而不是一个以上的路径可以为单个用户定义GOPATH,这是由于依赖性管理的增加而灰心的。

GOPATHsrcpkgbin下有三个著名目录。 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标准库由许多软件包组成,例如FMT,OS,Net等。

有一个特殊的软件包名称,main。该软件包包含main()函数,该功能是项目的入口点。每个旨在最终成为可执行文件的项目都必须包含main()功能,因此必须包含main软件包。

最好是在项目的根文件夹和自己目录中的其他软件包上声明主包装文件。

模块

一个模块是相关的GO软件包的集合,将其一起版本为单个单元。模块记录精确的依赖性要求并创建可重复的构建。 GO模块由位于模块目录层次结构根部的go.mod文件定义。该文件定义了模块路径,这是模块中所有软件包的导入路径前缀,并指定了模块的依赖项,包括其他模块的必需版本。

他们允许将版本控制和释放一组软件包,并且还使依赖性版本的信息明确且易于管理。请注意,尽管版本为依赖项仍将在src中下载GOPATH范围中的src,默认情况下。。

总结一下,虽然软件包是在GO程序中构造和重复使用代码的一种方式,但模块是一个版本的软件包集合,也可以处理依赖关系管理。这允许每个GO项目都有自己的孤立且可重复的构建环境。

命名模块的约定

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

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

  1. 模块路径:模块路径应为模块的全球唯一标识符。它通常以相反的顺序为Internet域名的形式,然后以模块名称为单位。例如,github.com/littlejohnny65/example-module。从模块导入软件包时,模块路径被用作导入路径。

  2. 模块名称:模块名称是模块路径的最后一个组件。它应该是简短的,描述的,并且要遵守Go的命名惯例。建议使用没有下划线或混合库的小写字母。例如,examplemodule

  3. 版本化:模块名称本身不包括版本信息。模块的版本使用模块版本标识符(例如v1.2.3)在go.mod文件中分别指定。模块路径和版本标识符的组合唯一标识了模块的特定版本。

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

go.sum文件

当您运行像go get github.com/user/repo这样的命令时,GO工具将从该位置获取模块。这使得可以在支持Git,Mercurial,Bazaar或Subversion等版本控制系统的任何服务器上托管GO代码。
考虑到GO从外部存储库中下载依赖关系的非常灵活和直接的方法,为了确保依赖关系的完整性是为了创建一个本地文件,以存储每个依赖关系的校验和。这就是保证安装的依赖项完全相同的原因。

校验和文件是由本地go工具生成的,如果要确保依赖项将与本地环境完全相同,则应将推到外部环境,例如服务器和dockerfiles 。

模块化项目的文件树

/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项目:

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

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

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

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

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

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

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

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

包起来

模块化方法与与单个工作空间没有根本不同,但它在其基础上具有更大的灵活性和可管理性。模块允许您在文件系统中想要的任何地方都有一个项目,并且还可以使用命名级的依赖项以提高稳定性,但是它仍然使用gopath作为默认位置来存储依赖项和可执行文件。

总而言之,go.mod提供的模块化环境是GO开发人员工具箱中的一个强大工具,可以补充和扩展传统Gopath环境的功能。它表明,它适应了现代软件开发的日益复杂性和规模,这证明了该语言的持续发展以满足用户不断变化的需求。随着我们的前进,令人兴奋地想象GO的生态系统中将带来什么发展。