一边学习一边整理读书笔记,并与大家分享,侵权即删,谢谢支持!


在Go语言中,项目结构十分重要,因为它决定了项目内部包的布局及包依赖关系是否合理,同时还会影响到外部项目对该项目中包的依赖与引用。

5.1 Go项目的项目结构

我们先来看看第一个Go项目——Go语言自身——的项目结构是什么样的。

下面是Go 1.16版本src目录下的完整布局:

├── Make.dist
├── README.vendor
├── all.bash*
├── all.bat
├── all.rc*
├── bootstrap.bash*
├── buildall.bash*
├── clean.bash*
├── clean.bat
├── clean.rc*
├── cmd/
├── cmp.bash
├── go.mod
├── go.sum
├── internal/
├── make.bash*
├── make.bat
├── make.rc*
├── race.bash*
├── race.bat
├── run.bash*
├── run.bat
├── run.rc*
├── testdata/
...
└── vendor/
复制代码

5.2 Go语言典型项目结构

  1. Go项目结构的最小标准布局

Russ Cox在一个开源项目的issue中给出了他关于Go项目结构的最小标准布局的想法:

// 在Go项目仓库根路径下

- go.mod
- LICENSE
- xx.go
- yy.go
...
复制代码

- go.mod
- LICENSE
- package1
        - package1.go
- package2
        - package2.go
...
复制代码

这个布局很灵活,可以满足各种Go项目的需求。

  1. 以构建二进制可执行文件为目的的Go项目结构

Go社区在多年的Go语言实践积累后逐渐形成了一种典型项目结构,这种结构与Russ Cox的最小标准布局是兼容的,如图5-1所示。

图5-1 Go语言典型项目结构(以构建二进制可执行文件为目的的Go项目)

图5-1所示就是一个支持(在cmd下)构建二进制可执行文件的典型Go项目的结构。

  1. 以只构建库为目的的Go项目结构

我们来看一个典型的Go语言库类型项目的结构布局,见图5-2。

图5-2 Go语言库项目结构

去除了cmd和pkg两个子目录,vendor也不再是可选目录,库项目仅通过go.mod明确表述出该项目依赖的模块或包以及版本要求即可。

  1. 关于internal目录

在顶层放一个internal目录,将不想暴露到外部的包都放在该目录下,比如下面项目结构中的ilib1、ilib2:

// 带internal的Go库项目结构

$tree -F ./chapter2/sources/GoLibProj
GoLibProj
├── LICENSE
├── Makefile
├── README.md
├── go.mod
├── internal/
│  ├── ilib1/
│  └── ilib2/
├── lib.go
├── lib1/
│  └── lib1.go
└── lib2/
      └── lib2.go
复制代码

internal可以放在项目结构中的任一目录层级中,需项目结构设计人员明确哪些要暴露到外层代码,哪些仅用于同级目录或子目录中。