布局Go项目的合理方法是什么?

aus*_*eek 108 project go

我有一个开始变得更加复杂的go项目,并希望以减轻痛苦的方式放置文件系统.

有什么有意义的好例子吗?

Von*_*onC 126

2013年5月更新:官方文档位于" 代码组织 "部分

Go代码必须保存在工作区内.
工作空间是一个目录层次结构,其根目录有三个目录:

  • 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
Run Code Online (Sandbox Code Playgroud)

2014年7月更新:请参阅本约翰逊的 " 在Go中构建应用程序 "

该文章包括以下提示:

将二进制文件与应用程序分开

main.go文件和我的应用程序逻辑组合在同一个包中有两个结果:

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

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

camlistore/
  cmd/
    camget/
      main.go
    cammount/
      main.go
    camput/
      main.go
    camtool/
      main.go
Run Code Online (Sandbox Code Playgroud)

图书馆驱动发展

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

有时您可能希望用户以多种方式进行交互,因此您可以创建多个二进制文件.
例如,如果您有一个adder允许用户一起添加数字的" "软件包,您可能希望发布命令行版本以及Web版本.
您可以通过组织这样的项目轻松完成此操作:

adder/
  adder.go
  cmd/
    adder/
      main.go
    adder-server/
      main.go
Run Code Online (Sandbox Code Playgroud)

用户可以使用省略号"go get"安装"adder"应用程序二进制文件:

$ go get github.com/benbjohnson/adder/...
Run Code Online (Sandbox Code Playgroud)

瞧,你的用户安装了" adder"和" adder-server"!

不要对子包装发疯

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

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

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

对不起,我不能同意这种做法.
将类型分隔为文件有助于代码管理,可读性,可维护性和可测试性.
它也可以确保单一责任和开放/封闭原则的遵循......
不允许循环依赖的规则是强制我们有一个清晰的包结构.


(替代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
Run Code Online (Sandbox Code Playgroud)

下面的每个文件夹src/github.com/jmcvetta/都是单独的git checkout的根目录.

这引起了一些批评,在这个reddit页面中:

我强烈建议不要按照你的方式构建回购,它会破坏" go get",这是Go最有用的东西之一.
为知道Go的人编写代码要好得多,因为他们最有可能是编译它的人.
而对于那些不这样做的人,他们至少会对语言有所了解.

将主程序包放在repo的根目录中.
将资产放在子目录中(以保持整洁).
将代码的内容保存在子包中(如果有人想在二进制文件之外重用它).
在repo的根目录中包含一个安装脚本,以便于查找.

它仍然只是一个下载,构建,安装和设置的两步过程:

  • " go get <your repo path>":下载并安装go代码,以及资产的子目录
  • $GOPATH/<your repo path>/setup.sh:将资产分配到正确的位置并安装服务

  • `setup.sh`的一个(大)问题是Go是合理的跨平台而POSIX shell脚本不是. (15认同)

nem*_*emo 7

我认为,对于'project',你不是指Go包,而是你开发的软件.否则你可以在这里这里得到帮助.然而,为Go编写软件包并没有太大的不同:使用软件包,为每个软件包创建一个文件夹,并在应用程序中组合这些软件包.

为了建立自己的观点,你可以在github上查看趋势Go存储库:https://github.com/trending/go.值得注意的例子是凯利宙斯.

最流行的方案可能是在自己的目录中有一个主Go文件和许多模块和子模块.如果您有许多元文件(doc,license,templates,...),您可能希望将源代码放入子目录中.这就是我到目前为止所做的.