【问题标题】:When is it really necessary to place Go source code in $GOPATH/src?什么时候真的需要将 Go 源代码放在 $GOPATH/src 中?
【发布时间】:2017-04-19 14:26:48
【问题描述】:

看看这个 shell 会话,我在其中用 Go 构建了一个简单的 hello world 程序。

$ cd ~/lab/hello/
$ ls
hello.go
$ cat hello.go 
package main

import "fmt"

func main() {
    fmt.Printf("hello, world\n")
}
$ go build
$ ./hello 
hello, world
$ go env
GOARCH="amd64"
GOBIN=""
GOCHAR="6"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH=""
GORACE=""
GOROOT="/usr/lib/go"
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0"
CXX="g++"
CGO_ENABLED="1"
$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 8.7 (jessie)
Release:    8.7
Codename:   jessie

这是我不明白的。 https://golang.org/doc/install#testing 的教程说我应该将我的 hello.go 文件放在 ~/go/src/hello。但我没有遵循这一点。那么我的程序是如何编译的呢?如果我的程序以这种方式编译得很好,为什么文档说我应该将源代码保留在 ~/go/src 或 $GOPATH/src 似乎并不重要?

是否存在确实需要将源代码放在 $GOPATH/src 的场景?

【问题讨论】:

  • 阅读How to Write Go Code,它解释了这一切。
  • @MadWombat 正在遵循经过测试、验证、推荐的“愚蠢的”方式?如果一台机器的设计者告诉你:“你必须先按下这个按钮,然后你才能做 X。”您是否还要问有什么证据表明最好先按下按钮? “工具的创建者告诉你这样做”是否证据不足?好吧,可能不像在编程中自我那么强大。
  • 就是这样。编程语言不仅仅是一台机器,它还是一种工具。作为该工具的用户,我必须了解它是如何工作的,否则我无法使用它。所以不,我不会只是“按下按钮 X”,我需要确切地知道我为什么要这样做以及会发生什么。是的,强迫我使用域名作为目录名称来构建我的源代码是令人难以置信的愚蠢到被侮辱的地步。幸运的是,供应商支持消除了一些痛苦。
  • @Volker 你错过了这个问题的重点。这个问题不是关于我是否应该遵循文档所说的内容。这个问题是关于如果我不遵循文档,什么情况会给我带来问题。这将帮助我更好地理解遵循文档的有用性。

标签: go projects-and-solutions directory-structure


【解决方案1】:

标准 Go 工具在 $GOPATH 子目录 srcpkgbin 中查找。例如,

currency.go:

package main

import (
    "fmt"
    "time"

    "golang.org/x/text/currency"
)

func main() {
    t1799, _ := time.Parse("2006-01-02", "1799-01-01")
    for it := currency.Query(currency.Date(t1799)); it.Next(); {
        from := ""
        if t, ok := it.From(); ok {
            from = t.Format("2006-01-01")
        }
        fmt.Printf("%v is used in %v since: %v\n", it.Unit(), it.Region(), from)
    }
}

输出:

$ go build currency.go
currency.go:7:2: cannot find package "golang.org/x/text/currency" in any of:
    /home/peter/go/src/golang.org/x/text/currency (from $GOROOT)
    /home/peter/gopath/src/golang.org/x/text/currency (from $GOPATH)
$ 

如果我们将丢失的包放在$GOPATH/src 中,标准的 Go 工具会找到它。

$ go get golang.org/x/text/currency
$ go build currency.go
$ ./currency
GBP is used in GB since: 1694-07-07
GIP is used in GI since: 1713-01-01
USD is used in US since: 1792-01-01
$ 

【讨论】:

    【解决方案2】:

    真的需要将您的代码放入GOPATH,一旦您编写的代码超过了package main。当你 import "github.com/me/myapp/mylib" 时,Go 会在你的 GOPATH 下查找。 go test 之类的工具也适用于 GOPATH 下的包,而不是 .go 文件。

    一旦您的代码位于多个文件中,这也将成为更实际的做法。这就像通过直接调用cc/gcc/等来编译你的C程序的区别。并使用像make 这样的工具。

    如果您刚开始并想知道为什么人们首先要将项目分解为多个包,原因包括:

    • 项目不断增长,您确实需要组织 10K 或 100K 行。
    • 项目通常包含可重用的工具,并且包让其他项目import 单独使用它们。
    • 包让您可以跟踪和控制哪些代码可以访问哪些其他代码和变量。例如,一个包中的私有名称不能被其他包访问,所以你知道你可以在不破坏包外部代码的情况下搞乱这些私有的东西,并且你知道外面的代码不会与私有字段/变量或调用背后的私人代码。
    • 包最大限度地减少命名空间冲突,即,您可以使用gzip.Readerio.Reader。如果你选对了名字,packagename.ThingName 可以让代码自然阅读。
    • 可以单独重新编译、测试包等,从而使您的编辑/构建/测试周期更快。
    • 具体来说,在 Go 中,包会强制执行有关代码组织的其他一些事情,例如没有循环依赖项(如果 A 导入 B,B 不会直接或间接导入 A),并且 /foo/internal/ 下的包仅被以下包使用/foo/。像这样的限制有助于防止大型项目像意大利面条一样纠缠不清。

    还有其他好处,但这些应该有助于说明为什么值得养成这个习惯。可以在一个大包中提前编写一些东西,然后根据需要开始分解文件,将一些类型、函数等移到其他包中;随着时间的推移,“自然”界限将开始变得更有意义。

    【讨论】:

      【解决方案3】:

      正如 JimB 在评论中所说,Go documentation 清楚地说明了这一点;基本上,GOPATH 是工作区,它允许您将所有项目文件、导入和工件保存在一个位置。

      对于一个简单的项目,这并不是绝对必要的,但是当您开始导入依赖项并想要管理库时,它会变得更有帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-16
        • 2016-07-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多