177

即使我已经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
4

13 回答 13

185

它不起作用,因为您的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在终端中键入来调用它。
于 2012-11-04T22:26:58.177 回答
30

尽管关于需要将目录与包名称匹配的公认答案仍然是正确的,但您确实需要迁移到使用 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

您的代码无需位于 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

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

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

/my-app
├── go.mod
├── /src
   ├── /app
   |  └── main.go
   └── /utils
      └── utils.go

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

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

go 1.14

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

import "git.mydomain.com/path/to/repo/my-app/src/my-app"

(我正在使用带有 Golang 扩展的 VS Code。)

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

处理私人回购

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

于 2020-07-15T01:20:45.700 回答
14

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

go env -w  GO111MODULE=off

注意:设置 GO111MODULE=off 将关闭最新的 GO Modules 功能。

参考:为什么到处都是 GO111MODULE,以及关于 Go Modules 的一切(随 Go 1.17 更新)

GO111MODULE 与 Go 1.16

从 Go 1.16 开始,默认行为是 GO111MODULE=on,这意味着如果你想继续使用旧的 GOPATH 方式,你将不得不强制 Go 不使用 Go Modules 功能:

导出 GO111MODULE=off

于 2020-08-23T10:24:16.910 回答
10

编辑:因为您的意思是 GOPATH,请参阅fasmat回答(赞成)

正如“如何让 go find 我的包? ”中提到的,您需要将包xxx放在目录xxx中。

请参阅Go 语言规范

package math

一组共享相同PackageName形式的文件执行一个包。
一个实现可能要求一个包的所有源文件位于同一个目录中。

守则组织提到:

widget在构建导入包“ ”的程序时,该go命令src/pkg/widget会在 Go 根目录中查找,然后——如果在那里找不到包源——它会src/widget按顺序在每个工作区中搜索。

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


(原答案)

您还应该设置GOPATH为 ~/go,而不是GOROOT,如“如何编写 Go 代码”中所示。

Go 路径用于解析导入语句。它由 go/build 包实现并记录在案。

GOPATH环境变量列出了查找 Go 代码的位置。
在 Unix 上,该值是一个冒号分隔的字符串。
在 Windows 上,该值是以分号分隔的字符串。
在计划 9 中,值是一个列表。

这不同于GOROOT

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

于 2012-11-03T22:30:36.607 回答
9

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

于 2020-09-11T01:49:24.103 回答
3

TL;DR:遵循 Go 约定!(吸取教训),检查旧的 go 版本并删除它们。安装最新。

对我来说,解决方案是不同的。我在一个共享的 Linux 服务器上工作,在GOPATH多次验证了我的和其他环境变量之后,它仍然无法正常工作。我遇到了几个错误,包括“找不到包”和“无法识别的导入路径”。尝试按照golang.org上的说明使用解决方案重新安装后(包括卸载部分)仍然遇到问题。

我花了一些时间才意识到还有一个旧版本没有被卸载(go version然后which go再次运行...... DAHH)这让我想到了这个问题并最终解决了。

于 2018-01-31T07:43:04.487 回答
2

在不编辑 GOPATH 或任何东西的情况下,就我而言,只需执行以下操作:


/app
├── main.go
├── /utils
    └── utils.go

在需要的地方导入包。这可能不直观,因为它与应用程序路径无关。您还需要在包路径中添加应用程序:

main.go

package main

import(
   "app/util"  
)

在 app 目录中,运行:

go mod init app

go get <package/xxx>

go build main.go / go run main.go

你应该很高兴。


GOPATH =/home/go

应用路径 =/home/projects/app

创建一个适当的go.modgo.sumgo mod init app删除旧之前)

之后解决所有依赖项,例如缺少go get github.com/example/package.

于 2021-05-22T20:00:32.403 回答
1

如果您有一个有效的$GOROOT$GOPATH正在它们之外进行开发,则如果尚未下载包(您的或其他人的),您可能会收到此错误。

如果是这种情况,请尝试go get -d(-d 标志阻止安装)以确保在运行、构建或安装之前下载包。

于 2020-11-20T12:19:42.473 回答
0

对我来说,上述解决方案都没有奏效。但是我的 go 版本不是最新的。我已经下载了最新版本并在我的 mac os 中替换了旧版本,之后它运行良好。

于 2021-05-14T18:56:21.580 回答
0

简单来说,即使使用GO111MODULE=on也可以使用以下导入语法解决导入问题:

import <your_module_name>/<package_name>

your_module_name -> 模块名称,可以在模块的 go.mod 文件中作为第一行找到。

示例:github.com/nikhilg-hub/todo/ToDoBackend

package_name -> 模块内包的路径。

例子:orm

所以导入语句看起来像:

import "github.com/nikhilg-hub/todo/ToDoBackend/orm"

根据我的说法,我们需要指定模块名+包名,因为我们可能需要在两个或多个不同的模块中使用相同的包名。

注意:如果你从同一个模块导入一个包,你仍然需要像上面一样指定完整的导入路径。

于 2022-01-09T22:57:55.853 回答
0

我在构建 docker 文件时遇到了类似的问题:

[1/3] STEP 9/9: RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o manager main.go
api/v1alpha1/XXX.go:5:2: cannot find package "." in:
        /workspace/client/YYY/YYY.go

这仅在构建 Dockerfile 时出现,在本地构建工作正常。

问题原来是我的 Dockerfile 中缺少的语句:

COPY client/ client/
于 2022-02-08T13:23:01.210 回答
-1

跑步go env -w GO111MODULE=auto对我有用

于 2021-05-06T19:59:16.743 回答
-8

您是否尝试过将go的绝对目录添加到您的“路径”?

export PATH=$PATH:/directory/to/go/
于 2012-11-04T08:53:57.373 回答