我有一个开始变得更加复杂的Go项目,我想以这样的方式布置文件系统以减少痛苦.

有没有一些很好的例子来说明什么是有意义的?

推荐答案

更新:2013年5月:正式文件在"Code organization"一节

GO代码必须保存在workspace内.
工作区是在其根目录下有三个目录的目录层次 struct :

  • src包含组织成包(每个目录一个包)的GO源文件,
  • pkg包含包对象,并且
  • bin包含可执行命令.

go tool构建源包并将生成的二进制文件安装到pkgbin目录.

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文件和我的应用程序逻辑组合在同一个包中有两个后果:

  • 它使我的应用程序不能作为库使用.
  • 我只能有一个应用程序二进制文件.

我发现解决这个问题的最好方法就是在我的项目中使用一个"cmd"目录,其中每个子目录都是一个应用程序二进制文件.

camlistore/
  cmd/
    camget/
      main.go
    cammount/
      main.go
    camput/
      main.go
    camtool/
      main.go

图书馆驱动的发展

main.go文件移出根目录允许您从库的Angular 构建应用程序.您的应用程序二进制文件只是您的应用程序库的客户端.

有时您可能希望用户以多种方式交互,因此您创建了多个二进制文件.
例如,如果您有一个允许用户将数字相加的"adder"包,您可能需要发布命令行版本和Web版本.
通过按如下方式组织您的项目,您可以轻松地做到这一点:

adder/
  adder.go
  cmd/
    adder/
      main.go
    adder-server/
      main.go

用户可以使用省略号"go get"安装您的"加法器"应用程序二进制文件:

$ go get github.com/benbjohnson/adder/...

瞧,您的用户已经安装了"adder"和"adder-server"!

不要着迷于子套餐

通常,我的项目的类型都非常相关,因此从可用性和API的Angular 来看,它更适合.
这些类型还可以利用它们之间的未导出调用,从而使API保持小而清晰.

  1. 在每个文件中将相关类型和代码分组在一起.如果您的类型和功能组织得很好,那么我发现文件往往在200到500 SLOC之间.这听起来可能很多,但我发现它很容易导航.1000SLOC通常是我对单个文件的上限.
  2. 将最重要的类型组织在文件顶部,并在文件底部按重要性递减的方式添加类型.
  3. 一旦你的应用程序开始超过10000 SLOC,你就应该认真判断它是否可以被分解成更小的项目.

注意:最后的练习并不总是好的:

对不起,我就是不同意这种做法


(2013年2月备选方案,仅适用于src人)

The app and both libraries live on Github, each in its own repository.
$GOPATH is the root of the project - each of your Github repos will be checked out several folders below $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签出的根目录.

不过,这招致了一些批评,在这reddit page人中:

我强烈建议不要按照你现在的方式组织回购,它会打破"go get",这是围棋最有用的东西之一.
为了解围棋的人编写代码要好得多,因为他们最有可能是编译代码的人.
而对于那些不了解这种语言的人来说,他们至少可以感受一下这种语言.

将主包放在回购的根目录中.
将assets资源 放在子目录中(以保持整洁).
将代码的主要部分保存在子包中(以防任何人希望在您的二进制文件之外重用它).
在repo的根目录中包含一个设置脚本,这样很容易找到.

下载、构建、安装和设置仍然只需要两个步骤:

  • "go get <your repo path>":下载并安装GO代码,带有assets资源 的子目录
  • $GOPATH/<your repo path>/setup.sh:将assets资源 分发到正确的位置并安装服务

Go相关问答推荐

读取JSON数据并在网页上显示

go中跨域自定义验证的问题

日志(log)文件不在 golang 的日志(log)目录中

未实现的 desc = 未知服务 pb.AuthService 我的简单身份验证服务器上出现错误

Golang Fiber Render - 将数据发送到多个布局

无效操作:v > max(类型参数 T 与 > 不可比较)

在 Go 中将元数据从一个 JPEG 复制到另一个

如何在正则表达式中使整个单词可选?

在VSCode中如何使用特定的文件名提供编译命令

使用反射在Go中递归迭代 struct 体和集合字段

使用Cookie身份验证的Gorilla Golang Websocket优化

golang gin 获取 cookie json

在 Go 中公开公共 JWK

通过环境变量配置 OTLP 导出器

如果 transaction.Commit 对带有 postgres 连接的 SQL 失败,您是否需要调用 transaction.RollBack

如何在 golang revel 中获取动态应用程序配置

如何从 tinygo webassembly 目标返回对象

如何在 Gorm 中获得特定日期的最大值?

在 VSCode 中使用命令行参数调试 Go 测试

如何允许可转换为指针的泛型类型参数化另一种可转换为指针的泛型类型?