golang 项目结构
常见的golang代码布局方式通常有扁平化布局和模块化布局。
扁平化布局
扁平化布局很简单,代码之间不分层,所有代码放在同一个目录。这种布局风格适合比较简单的项目。我们见到的工具包通常就是这种布局,例如 errors 项目的结构:
project
|
|- bench_test.go
|
|-errors.go
|
|-errors_test.go
|
|-example_test.go
|
|-format_test.go
|
|-go113.go
|
|-go113_test.go
|
|-json_test.go
|
|-stack.go
|
|-stack_test.go
值得注意的是,工具包中尽量不要有第三方依赖,否则,维护工具包中的第三方依赖会很麻烦,也很容易给其他项目带来版本冲突等问题。
模块化布局
项目稍微复杂一些之后,扁平化布局会显得比较混乱,我们通常会按功能将代码放到不同的目录中,也就是模块化的布局方式。从 1.14 版本之后,官方推荐使用 [Go Modules](https://blog.golang.org/using-go-modules)
管理依赖,项目一般会由 cmd
、 internal
、 pkg
、 vendor
等目录组成,当然这不是官方建议的项目结构,只是目前比较常见的布局方式。
project
|
|-- cmd/
| |
| |-- app1/
| | |
| | |- main.go
| | |
| | |- handler/
| |
| |-- app2/
| |
| |- main.go
| |
| |- handler/
|
|-- internal/
| |
| |-- pkg
| | |
| | |-- data
| | |
| | |-- log
| |
| |-- router
| |
| |-- service
|
|-- pkg/
| |
| |-- kit
|
|-- vendor/
|
|-- go.mod
|
|-- go.sum
cmd/
cmd
目录项目中的可执行程序的入口,主要放置 main()
函数,每个可执行程序对应一个子文件夹,文件夹应以程序的名称命名,可以在名字后面加字母 d
,表示程序将以守护进程的方式运行。应用程序中必须包含一个 main()
函数的源文件,即 demo 中的 main.go
,文件名字最好与程序名字一致。cmd
包可能会导入 internal
、pkg
或 vendor
包中的代码。
internal/
internal
目录是项目私有的代码。 1.4 版本新增了 Internal packages 特性,internal
目录中的代码只能被 internal
目录的父目录下的子目录引用,举个例子 .../a/b/c/internal/d/e/f
仅仅可以被 .../a/b/c
下的目录导入,.../a/b/g
则不允许。除了 internal
根目录之外,也可以在任何目录下创建 internal
目录。
pkg/
放在 pkg
目录下的代码可以被其他项目直接导入。可以理解为 internal
目录下的代码是项目的私有代码,而 pkg
目录下的代码是开放的代码。如果项目中不包含公共的代码,则可以不需要 pkg
包。而且如果项目足够小,或者项目只是一个工具包,也完全不需要 pkg
包。
vendor/
存放项目依赖的目录,通常是依赖管理工具自己来维护。例如, go mod vendor
命令会将项目的依赖放到 vendor
目录。
其他目录
不同类型的项目通常还包括其他的一些目录,比如服务型项目通常会有一个 api
目录,web 项目通常会有一个 web
目录以存放静态资源,工具包类型的项目通常会包含一个 examples
目录。
总结
这篇文章简单的描述了常见的 golang 项目布局方式,实际项目中,不一定要按照这两种方式来组织代码结构,一切以实际项目为准。先让代码能跑起来, 再试图让它变得更好,最后再试着让它变得更快。