Go build:"找不到包"(即使设置了GOPATH)

Mit*_*lad 111 build package go

即使我已经GOPATH正确设置,我仍然无法"go build"或"go run"来找到我自己的包.我究竟做错了什么?

$ echo $GOROOT
/usr/local/go

$ echo $GOPATH
/home/mitchell/go

$ cat ~/main.go
package main
import "foobar"
func main() { }

$ cat /home/mitchell/go/src/foobar.go
package foobar

$ go build main.go
main.go:3:8: import "foobar": cannot find package
Run Code Online (Sandbox Code Playgroud)

fas*_*mat 141

它不起作用,因为您的foobar.go源文件不在名为的目录中foobar.go buildgo install尝试匹配目录,而不是源文件.

  1. 设置$GOPATH为有效目录,例如export GOPATH="$HOME/go"
  2. 移动foobar.go$GOPATH/src/foobar/foobar.go与建筑应该只是罚款.

其他建议步骤:

  1. 加入$GOPATH/bin$PATH的:PATH="$GOPATH/bin:$PATH"
  2. 移动main.go$GOPATH/src例如的子文件夹$GOPATH/src/test
  3. go install test现在应该创建一个可执行文件$GOPATH/bin,可以通过test在终端中输入来调用.

  • 这不是一个bug吗?我的 `GOPATH=/usr/local/go-pkgs`,所以 Go 在 `/usr/local/go-pkgs/src/<package-name>` 中查找源代码,但 `go get` 将其放在 `/ usr/local/go-pkgs/src/gopkg.in/<package-name>`。为什么我必须在安装后手动移动所有软件包?那太愚蠢了。 (4认同)
  • `go get`通常将包放入`$ GOPATH/src /`所以如果你调用`go get domain.com/path/to/package`,它最终会在`$ GOPATH/src/domain.com/path /中/ package`.我想你试图从`gopkg.in`获取一个包?如果这样绝对是预期的行为,你应该用他们的全名导入它们; 例如`import"gopkg.in/yaml.v1"`以及[在文档中描述](https://gopkg.in/yaml.v1). (2认同)

dev*_*ost 20

尽管关于需要将目录与包名称匹配的公认答案仍然是正确的,但您确实需要迁移到使用 Go 模块而不是使用 GOPATH。遇到此问题的新用户可能会对使用 GOPATH(就像我一样)的提及感到困惑,这些现在已经过时了。因此,我将尝试解决这个问题,并在使用 Go 模块时提供与防止这个问题相关的指导。

如果您已经熟悉 Go 模块并且遇到了这个问题,请跳到我下面更具体的部分,其中涵盖了一些容易忽略或忘记的 Go 约定。

本指南讲授 Go 模块:https : //golang.org/doc/code.html

使用 Go 模块组织项目

迁移到 Go 模块后,如该文章中所述,按所述组织项目代码:

一个存储库包含一个或多个模块。模块是一起发布的相关 Go 包的集合。Go 存储库通常只包含一个模块,位于存储库的根目录。一个名为 go.mod 的文件声明了模块路径:模块中所有包的导入路径前缀。该模块在包含其 go.mod 文件的目录中包含包以及该目录的子目录,直到包含另一个 go.mod 文件(如果有)的下一个子目录。

每个模块的路径不仅用作其包的导入路径前缀,而且还指示 go 命令应该在哪里下载它。例如,为了下载模块 golang.org/x/tools,go 命令将查询https://golang.org/x/tools指示的存储库(此处有更多描述)。

导入路径是用于导入包的字符串。包的导入路径是其模块路径与其在模块内的子目录相连。例如,模块 github.com/google/go-cmp 在目录 cmp/ 中包含一个包。该包的导入路径是 github.com/google/go-cmp/cmp。标准库中的包没有模块路径前缀。

你可以像这样初始化你的模块:

$ go mod init github.com/mitchell/foo-app
Run Code Online (Sandbox Code Playgroud)

您的代码无需位于 github.com 上即可构建。但是,将模块构建为最终将发布的结构是最佳实践。

了解尝试获取包裹时会发生什么

这里有一篇很棒的文章讨论了当您尝试获取包或模块时会发生什么:https : //medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16 它讨论了包的存储位置以及将如果你已经在使用 Go 模块,帮助你理解为什么你可能会收到这个错误。

确保导入的函数已经导出

请注意,如果您在从另一个文件访问函数时遇到问题,则需要确保已导出函数。如我提供的第一个链接中所述,函数必须以大写字母开头才能导出并可以导入到其他包中。

目录名称

另一个关键细节(如已接受的答案中所述)是目录名称定义了包的名称。(你的包名需要符合他们的目录名)。你可以在这里看到这样的例子:https://medium.com/rungo/everything-you-need-to-know-about-packages-in-go-b8bac62b74cc 随着也就是说,包含您的main方法(即您的应用程序的入口点)的文件在某种程度上不受此要求的约束。

例如,在使用这样的结构时,我的导入有问题:

/my-app
??? go.mod
??? /src
   ??? main.go
   ??? /utils
      ??? utils.go
Run Code Online (Sandbox Code Playgroud)

我无法将代码导入utils到我的main包中。

但是,一旦我放入main.go它自己的子目录,如下所示,我的导入工作得很好:

/my-app
??? go.mod
??? /src
   ??? /app
   |  ??? main.go
   ??? /utils
      ??? utils.go
Run Code Online (Sandbox Code Playgroud)

在该示例中,我的 go.mod 文件如下所示:

module git.mydomain.com/path/to/repo/my-app

go 1.14
Run Code Online (Sandbox Code Playgroud)

当我在添加对 的引用后保存 main.go 时utils.MyFunction(),我的 IDE 会自动拉入对我的包的引用,如下所示:

import "git.mydomain.com/path/to/repo/my-app/src/my-app"
Run Code Online (Sandbox Code Playgroud)

(我将 VS Code 与 Golang 扩展一起使用。)

请注意,导入路径包含包的子目录。

处理私人回购

如果代码是私有存储库的一部分,则需要运行 git 命令以启用访问。否则,您可能会遇到其他错误本文提到如何为私有 Github、BitBucket 和 GitLab 存储库执行此操作:https ://medium.com/cloud-native-the-gathering/go-modules-with-private-git- repositories-dfe795068db4 这里也讨论了这个问题:“获取”私有存储库的正确方法是什么?


Von*_*onC 10

编辑:既然你的意思是GOPATH,请参阅fasmat回答(upvoted)

如" 我如何找到我的包? "中所述,您需要将包xxx放在目录中xxx.

请参阅Go语言规范:

package math
Run Code Online (Sandbox Code Playgroud)

共享相同的一组文件PackageName形成包的实现.
实现可能要求包的所有源文件都位于同一目录中.

代码组织提到:

当构建导入包" widget"的程序时,该go命令src/pkg/widget在Go根目录中查找,然后 - 如果在那里找不到包源 - 它src/widget按顺序搜索每个工作空间内部.

("工作区"是您的路径条目GOPATH:该变量可以引用您的' src, bin, pkg'的多个路径)


(原始答案)

你也应该设置 GOPATH为〜/ go,而不是GOROOT如" 如何编写Go代码 "中所示.

Go路径用于解析import语句.它由go/build包实现并记录.

GOPATH环境变量列表地方寻找Go代码.
在Unix上,该值是以冒号分隔的字符串.
在Windows上,该值是以分号分隔的字符串.
在计划9中,值是一个列表.

这不同于GOROOT:

Go二进制发行版假设它们将安装在/usr/local/go(或c:\Go在Windows下),但可以将它们安装在不同的位置.
如果这样做,则需要GOROOT在使用Go工具时将环境变量设置为该目录.

  • 设置GOPATH还有[简短视频介绍](https://www.youtube.com/watch?feature=player_embedded&v=XCsL89YtqCs&noredirect=1) (4认同)

小智 10

我通过将 go env GO111MODULE 设置为 off 解决了这个问题

go env -w  GO111MODULE=off
Run Code Online (Sandbox Code Playgroud)


Sur*_*rya 7

在 1.14 之后的最新 go 版本中,我们必须go mod vendor在构建或运行之前执行此操作,因为默认情况下 go 附加-mod=vendor到 go 命令。所以做完之后go mod vendor,如果我们尝试构建,我们就不会遇到这个问题。

  • 我希望这很快就会出现在搜索结果的较高位置,因为这正是我需要知道的。 (2认同)
  • 这有效!去 v1.17 。您能详细解释一下这里实际发生的情况吗? (2认同)