一个 Go 项目可能包含多个具有不同包名的文件。在这些情况下设置适当的布局在 Go 中并不总是那么简单,尤其是对于初学者而言。这篇文章将通过特定用例场景的快速概览和动手示例,因此人们不仅能够理解背后的概念,而且能够为 Go 项目创建适当的布局。

对于目录结构或如何以特定方式组织 Go 项目文件没有严格的规则。这实际上是一个好主意,也是一个坏主意。不好是因为容易弄得一团糟,好是因为一个项目的组织结构可以根据程序员的口味来搭建。

然而,没有责任的自由可能是一团糟。Go 程序员通常遵循某些模式来布置项目中的文件和目录。这也因项目而异。他们遵循这些模式,因为它不仅适用于他们,也适用于他们的程序员伙伴。遵循特定系统的每个人不仅富有成效,而且合作起来也很有趣。在进入项目布局之前,让我们了解一下我们遇到的与 Go 项目相关的一些基本元素。对于初学者来说,其中之一是模块。

Go 中的模块是什么?

在典型的 Go 项目中,开发人员应该做的第一件事是创建一个带有项目名称的目录。虽然没有严格的规定,但程序员应该尽量保持目录名与项目名相同。该目录将包含与项目相关的每个文件和其他子目录:

$ mkdir go-demoproject
$ cd go-demoproject

Go 开发人员通常做的下一件事是使用与模块相关的go 工具命令。例如,如果我们想在当前目录中初始化新模块。例如,如果我们想使用github.com/xyzuser/go-demoproject初始化模块,我们可以编写以下代码:

go mod init github.com/xyzuser/go-demoproject

这将在当前目录中创建两个文件:go.mod和go.sum。两者实际上都是简单的文本文件,可以使用任何文本编辑器打开。

因此,根据定义,模块是存储在文件树中的 Go 包的集合,其根目录为go.mod文件。go.mod文件定义了导入依赖第三方文件的模块路径,以及成功构建应用程序所需的其他模块。这与 C++ 中使用的命名空间或多或少相同,将一个模块中的应用程序与另一个模块的相同应用程序分开,可能是由于版本号不同。

Go 中的 go.mod 文件

Go 模块由go.mod文件定义,该文件描述了模块属性、Go 版本以及该项目对其他模块的依赖关系。属性包括:

当前模块的模块路径,go工具可以下载模块的位置,例如模块代码的仓库位置。在多个模块的版本号的情况下,这也可用作唯一标识符。还包括模块中所有包的包路径前缀。
当前模块所需的最小 Go 版本号。
关于如何用另一个模块版本替换当前模块的可选说明。
假设,在我们的go-demoproject中,我们依赖于其他一些模块,例如gorilla/mux、gorm和 MySQL 作为后端数据库。这些第三方模块需要从它们各自的存储库中下载到本地机器的模块缓存中。在构建应用程序时,这些模块被复制到我们的项目中。所以我们通常键入以下命令:

go get “github.com/jinzhu/gorm”
go get  “github.com/jinzhu/gorm/dialects/mysql”
go get  “github.com/gorilla/mux”

默认情况下,这些模块实际上是下载并存储在go子目录中的,该子目录位于本地计算机的主目录中。go.mod文件中的指令现在看起来像这样:

go.mod

module github.com/xyzuser/go-demoproject

go 1.18

require (
    github.com/go-sql-driver/mysql v1.5.0 // indirect
    github.com/gorilla/mux v1.8.0 // indirect
    github.com/jinzhu/gorm v1.9.16 // indirect
    github.com/jinzhu/inflection v1.0.0 // indirect
)

如我们所见,该文件定义:

  • 模块路径
  • 用于创建此模块文件的 Go 版本
  • 成功构建的项目依赖要求并将它们锁定到特定的版本号

注意后缀- // 间接。依赖模块可以有两种类型:直接和间接:

  • 如果模块的依赖是直接导入的,那就是直接依赖
  • 如果模块的直接依赖导入了一些其他依赖的模块,则它是间接依赖。如果一个模块在go.mod文件中被提及但没有被模块的任何源代码文件导入,那么它也被视为间接依赖

Go 中的 go.sum 文件

go.sum文件是另一个自动生成的依赖项锁定文件,其中列出了项目所需的直接和独立依赖项及其版本号。顺便说一句,go.mod文件还不足以成功构建应用程序吗?go.sum文件列出了额外的信息,例如使用每个直接和间接依赖项的校验和进行验证的校验和。

我们一直在创建的go-demoproject具有以下自动生成的go.sum文件。这个文件是在我们使用命令go mod init时自动生成的。在我的例子中,这些是自动生成列表中的示例行:

github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=

...

在 Go 中布局项目文件

更好的组织 Go 项目的方法是将相关的 Go 代码文件放在项目主目录下的子目录中,以便项目的其他部分能够找到 API 并使用它们。将所有源文件保存在同一目录下并不是一个好主意,即使您可以这样做。这利用了干净整洁的代码——这是非常重要的,因为更有经验的编码人员会知道。

现在,回到我们的go-demoproject。让我们组织目录结构。由于从外观上看(因为我们已经导入了 gorilla/mux 和 gorm 和 mysql 方言),该项目是一个带有后端数据库的 Web 应用程序,我们希望将目录树结构设置如下。理解这是一个示例指南——如果程序员选择以不同的方式执行它是可以的,但它应该有意义且逻辑一致地完成。这就是我想说的。

如前所述,这是示例的目录树结构,也是特定的项目类型。项目的根目录被赋予项目名称(go-demoproject)。其他都是这个目录的子目录和子目录。cmd文件夹包含main包,而main.go 文件又包含main.go文件,从该文件开始执行。pkg子目录包含我们将在应用程序中使用的所有本地包;他们被赋予其内容文件的相关名称。注意go.mod和go.sum文件是直接在项目根目录下创建的。

关于 Go 包布局的最终想法

一个项目通常包含排列成多个包和其他资源的多个源文件。除非组织得当,否则要想弄清楚什么去哪里,这可能是一场噩梦。虽然不是很明显,但是布局一个合适的项目目录结构其实很简单。一个简单的提示或指向正确方向的指针可以解决很多问题,至少在初始阶段是这样。还有一个提示——目录和文件的命名方案应该简单而有意义,并且应该放在正确命名的包中。