我有一个开始变得更加复杂的 go 项目,并希望以一种减少痛苦的方式布置文件系统。
有没有一些很好的例子说明什么是有意义的?
2013 年 5 月更新:官方文档位于“代码组织”部分
Go 代码必须保存在工作区中。
工作区是一个目录层次结构,其根目录有三个目录:
src
包含组织成包的 Go 源文件(每个目录一个包),pkg
包含包对象,并且bin
包含可执行命令。构建源包并将生成的
go tool
二进制文件安装到pkg
和bin
目录。该
src
子目录通常包含多个版本控制存储库(例如 Git 或 Mercurial),用于跟踪一个或多个源包的开发。
bin/
streak # command executable
todo # command executable
pkg/
linux_amd64/
code.google.com/p/goauth2/
oauth.a # package object
github.com/nf/todo/
task.a # package object
src/
code.google.com/p/goauth2/
.hg/ # mercurial repository metadata
oauth/
oauth.go # package source
oauth_test.go # test source
2014 年 7 月更新:参见Ben Johnson的“ Structuring Applications in Go ”
该文章包括以下提示:
将
main.go
文件和我的应用程序逻辑组合在同一个包中会产生两个后果:
- 它使我的应用程序无法用作库。
- 我只能拥有一个应用程序二进制文件。
我发现解决此问题的最佳方法是在我的项目中简单地使用“<code>cmd”目录,其中每个子目录都是应用程序二进制文件。
camlistore/
cmd/
camget/
main.go
cammount/
main.go
camput/
main.go
camtool/
main.go
将
main.go
文件移出根目录允许您从库的角度构建应用程序。您的应用程序二进制文件只是应用程序库的客户端。有时您可能希望用户以多种方式进行交互,因此您创建了多个二进制文件。
例如,如果您有一个“<code>adder”包,可以让用户将数字相加,您可能希望发布命令行版本和 Web 版本。
您可以通过像这样组织项目来轻松做到这一点:
adder/
adder.go
cmd/
adder/
main.go
adder-server/
main.go
用户可以使用省略号通过“go get”安装您的“adder”应用程序二进制文件:
$ go get github.com/benbjohnson/adder/...
瞧,您的用户安装了“<code>adder”和“<code>adder-server”!
通常我的项目类型都非常相关,因此从可用性和 API 的角度来看它更适合。
这些类型还可以利用它们之间的未导出调用,从而保持 API 小而清晰。
- 在每个文件中将相关类型和代码组合在一起。如果您的类型和功能组织良好,那么我发现文件往往在 200 到 500 SLOC 之间。这听起来可能很多,但我发现它很容易导航。1000 SLOC 通常是我单个文件的上限。
- 在文件顶部组织最重要的类型,并在文件底部添加重要性递减的类型。
- 一旦你的应用程序开始超过 10,000 SLOC,你应该认真评估它是否可以分解成更小的项目。
注意:最后的做法并不总是好的:
抱歉,我不能同意这种做法。
将类型与文件分离有助于代码管理、可读性、可维护性和可测试性。
它还可以确保单一责任和遵循开放/封闭原则......<br> 不允许循环依赖的规则是强制我们有一个清晰的包结构。
(2013 年 2 月的替代方案,src
仅关于)您可以在“ GitHub 代码布局
”
中找到说明的经典布局:
该应用程序和两个库都位于 Github 上,每个库都位于自己的存储库中。
$GOPATH
是项目的根目录 - 您的每个 Github 存储库都将在下面的几个文件夹中检出$GOPATH
。您的代码布局如下所示:
$GOPATH/
src/
github.com/
jmcvetta/
useless/
.git/
useless.go
useless_test.go
README.md
uselessd/
.git/
uselessd.go
uselessd_test.go
README.md
下的每个文件夹
src/github.com/jmcvetta/
都是单独 git checkout 的根目录。
不过,在这个reddit 页面中,这引起了一些批评:
我强烈建议不要按照你的方式构建 repo,它会破坏“
go get
”,这是 Go 中最有用的东西之一。
为知道 Go 的人编写代码要好得多,因为他们最有可能是编译它的人。
而对于那些不知道的人,他们至少会对这种语言有所了解。将主包放在 repo 的根目录中。
将资产放在子目录中(以保持整洁)。
将代码的主体保留在一个子包中(以防有人想在您的二进制文件之外重用它)。
在 repo 的根目录中包含一个安装脚本,以便于查找。下载、构建、安装和设置仍然只有两步过程:
- "
go get <your repo path>
": 下载并安装 go 代码,带有资产的子目录$GOPATH/<your repo path>/setup.sh
:将资产分配到正确的位置并安装服务
我假设对于“项目”,您的意思不是 Go 包,而是您开发的软件。否则,您可以在这里和这里获得帮助。然而,为 Go 编写包并没有太大的不同:使用包,为每个包创建一个文件夹并将这些包组合到您的应用程序中。
要建立自己的观点,您可以查看 github 上的热门 Go 存储库:https ://github.com/trending/go 。著名的例子是cayley 和zeus。
最流行的方案可能是在自己的目录中拥有一个主 Go 文件和许多模块和子模块。如果您有许多元文件(文档、许可证、模板等),您可能希望将源代码放入子目录中。这就是我到目前为止所做的。
Golang 的作者推荐了一种方法,它定义了如何布局代码以最好地使用 go 工具并支持源代码控制系统
您可能还应该看看这个 repo。它展示了很多如何构建 Go 应用程序的想法:https ://github.com/golang-standards/project-layout