组织一个多文件Go项目[关闭]


238

注意:这个问题与有关,但是两年在Go历史上是很长的时间。

在开发过程中组织Go项目的标准方法是什么?

我的项目是一个包mypack,所以我想我将所有.go文件放在一个mypack目录中。

但是,然后,我想在开发过程中对其进行测试,因此至少需要一个声明该main包的文件,以便我可以go run trypack.go

我应该如何组织呢?go install mypack每次尝试都需要做吗?


14
这段简短的截屏非常棒:youtube.com/watch?v=XCsL89YtqCs
Matt

是了解如何使用包组织项目的另一个有用链接。我认为,比官方的“如何编写go”代码更容易遵循。
IamNaN 2015年

对于新的Go模块系统,此答案涵盖模块结构,在模块内安排软件包,在单个存储库中是否具有多个模块等。最终,将为模块更新正式的“如何编写Go代码”介绍文档,但尚未发生。(如果您不熟悉Go和Go模块,则在阅读有关模块的更多信息之前,仍然应该阅读“如何编写Go代码”文档,因为许多模块文档都假定您熟悉GOPATH)。
典型182

Answers:


171

我建议阅读有关如何编写Go代码的页面

它记录了如何以go build友好的方式构建项目以及如何编写测试。使用该main程序包不必进行cmd测试。它们可以简单地被TestX命名为每个程序包的一部分,然后go test发现它们。

现在,随着Go 1的发布,问题中该链接中建议的结构有些过时了,您不再需要在pkg目录下放置目录src。仅有3个与规范相关的目录是GOPATH根目录中的3个目录:bin,pkg,src。在src之下,您可以简单地放置您的项目mypack,并且在其下是所有.go文件,包括mypack_test.go

go build 然后将其构建到根级别pkg和bin中。

因此,您的GOPATH可能如下所示:

~/projects/
    bin/
    pkg/
    src/
      mypack/
        foo.go
        bar.go
        mypack_test.go

export GOPATH=$HOME/projects

$ go build mypack
$ go test mypack

更新:从> = Go 1.11开始,模块系统现在已成为工具的标准部分,并且GOPATH概念已接近过时。


26
导出变量时,请使用$ HOME而不是〜。
Johan S

6
为什么在导出变量时建议将$ HOME推荐为〜?
425nesp

8
因为〜不是变量,所以只是别名。
皮尔2014年

6
@ 425nesp Johan弄错了-不是。外壳各不相同,但是设置环境变量时bash会扩展~,例如busybox bourne外壳也会扩展。自己尝试:export BOB=~ && env | grep ^BOB会屈服BOB=/your/homedir
Austin Adams

1
$HOME然后在更多的炮弹中工作~,例如在fish
houiui

60

jdi拥有有关的使用的正确信息GOPATH。我还要补充一点,如果您也打算使用二进制文件,则可能要在目录中添加一个附加级别。

~/projects/src/
    myproj/
        mypack/
            lib.go
            lib_test.go
            ...
        myapp/
            main.go

运行go build myproj/mypack将构建mypack程序包及其依赖关系运行go build myproj/myapp将构建myapp二进制文件及其依赖关系(可能包括mypack库)。


如果他确实有一个主cmd,这当然是有道理的。似乎他只是在创建一个库包。
jdi 2012年

50

我研究了许多Go项目,并且有很多变化。您可以分辨出谁来自C和谁来自Java,因为前者几乎将main包中项目根目录中的所有内容转储,而后者往往将所有内容都放在src目录中。但是,这都不是最佳选择。每一种都有其后果,因为它们会影响导入路径以及其他人如何重用它们。

为了获得最佳结果,我制定了以下方法。

myproj/
  main/
    mypack.go
  mypack.go

哪里mypack.gopackage mypackmain/mypack.go是(明显)package main

如果您需要其他支持文件,则有两种选择。要么将它们全部保留在根目录中,要么将私有支持文件放置在lib子目录中。例如

myproj/
  main/
    mypack.go
  myextras/
    someextra.go
  mypack.go
  mysupport.go

要么

myproj.org/
  lib/
    mysupport.go
    myextras/
      someextra.go
  main/
    mypack.go
  mypage.go

lib如果文件不打算由其他项目导入,则仅将其放在目录中。换句话说,如果它们是私人支持文件。这就是lib将-公用接口与专用接口分开的想法。

通过这种方式进行操作将为您提供一个不错的导入路径,myproj.org/mypack以便在其他项目中重用代码。如果使用,lib则内部支持文件将具有一个表示该文件的导入路径myproj.org/lib/mysupport

当建设项目,使用main/mypack,例如go build main/mypack。如果您有多个可执行文件,则也可以将其分开,main而不必创建单独的项目。例如main/myfoo/myfoo.gomain/mybar/mybar.go


14
Idomatic cmd/nameOfMyExecutable将为主软件包使用一个子目录(仅cmd/…在您有多个命令时才需要;请参见golang.org/x/tools/cmd;否则,经常main.go在顶层交换它并在顶层使用)。您拥有的方式go install将创建一个“ main”(或“ main.exe”)可执行文件。同样,惯用方法是internal在程序包/程序内部的子程序包中使用一个子目录,该子目录不打算在其他地方使用(预计Go的未来版本将不会再强制其他人以internal这种方式导入程序包)。
Dave C


13

似乎没有组织Go项目的标准方法,但是https://golang.org/doc/code.html指定了大多数项目的最佳实践。jdi的回答很好,但是如果您使用github或bitbucket并且还具有其他库,则应创建以下结构:

~/projects/
bin/
pkg/
src/
  github.com/
    username/
        mypack/
            foo.go
            bar.go
            mypack_test.go
        mylib/
            utillib.go
            utillib_test.go

通过这种方式,您可以为mylib创建一个单独的存储库,该存储库可用于其他项目,并且可以通过“ go get”进行检索。您的mypack项目可以使用“ github.com/username/mylib”导入您的库。想要查询更多的信息:

http://www.alexvictorchan.com/2014/11/06/go-project-structure/


6

将文件保留在同一目录中,并package main在所有文件中使用。

myproj/
   your-program/
      main.go
      lib.go

然后运行:

~/myproj/your-program$ go build && ./your-program

这怎么工作?您的main.go需要是包主程序;大概lib.go在不同的软件包中,然后go工具抱怨您不能在一个文件夹中拥有两个软件包。
I822014年

1
@ I82Much OP要求如何将一个程序包(主程序)划分为多个文件。在这种情况下,lib.go位于同一软件包中。
古斯塔夫

谢谢您的澄清。
I822014年

@古斯塔夫,我有同样的问题。看来,如果我将main软件包放在lib.go中,在main.go中,我将无法调用lib.go中定义的函数。
钱陈

@ElgsQianChen方法必须公开,必须以大写字母开头。例如MyMethod()或MyStruct {...}。
古斯塔夫2014年

6

让我们探究该go get repository_remote_url命令如何在下管理项目结构$GOPATH。如果执行此操作go get github.com/gohugoio/hugo,它将在以下位置克隆存储库

$ GOPATH / src / repository_remote / user_name / project_name


$ GOPATH / src / github.com/gohugoio/hugo

这是创建初始项目路径的好方法。现在,让我们探索那里的项目类型是什么以及它们的内部结构如何组织。社区中的所有golang项目都可以归类为

  • Libraries (无可执行二进制文件)
  • Single Project (仅包含1个可执行二进制文件)
  • Tooling Projects (包含多个可执行二进制文件)

通常,golang项目文件可以按照任何设计原则打包,例如DDDPOD

大多数可用的go项目都遵循此面向包的设计

面向包的设计鼓励开发人员将实现仅保留在自己的包中,而不是/internal那些包之间无法通信的包


图书馆

  • 数据库驱动程序qt之类的项目可以归为此类。
  • 现在,某些库(例如color)采用的是扁平结构,没有任何其他软件包。
  • 这些库项目大多数都管理一个称为internal的软件包。
  • /internal 包主要用于隐藏其他项目的实现。
  • 没有任何可执行的二进制文件,因此没有包含main func的文件。

 ~/$GOPATH/
    bin/
    pkg/
    src/
      repository_remote/
        user_name/
            project_name/
              internal/
              other_pkg/

单一专案

  • 诸如hugoetcd之类的项目在root级别和具有单个主要功能。
  • 目标是生成一个单一的二进制文件

工具项目

  • 项目如kubernetes去-复仇具有了一个叫做下组织主FUNC CMD
  • cmd/ 软件包管理我们要构建的二进制文件(工具)的数量

 ~/$GOPATH/
    bin/
    pkg/
    src/
      repository_remote/
        user_name/
            project_name/
              cmd/
                binary_one/
                   main.go
                binary_two/
                   main.go
                binary_three/
                   main.go
              other_pkg/
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.