英文:
Relative import from parent directory
问题
如何从父目录进行相对导入?
从meme/cmd/meme
:
import "../../../meme"
这会产生一个模糊的错误:
matt@stanley:~/gopath/src/bitbucket.org/anacrolix/meme/cmd/meme$ go get bitbucket.org/anacrolix/meme/cmd/meme
can't load package: /home/matt/gopath/src/bitbucket.org/anacrolix/meme/cmd/meme/main.go:8:2: local import "../../../meme" in non-local package
matt@stanley:~/gopath/src/bitbucket.org/anacrolix/meme/cmd/meme$ echo $GOPATH
/home/matt/gopath
如何从父目录本地导入?
英文:
How does one do a relative import from a parent directory?
From meme/cmd/meme
:
import "../../../meme"
This gives an ambiguous error:
matt@stanley:~/gopath/src/bitbucket.org/anacrolix/meme/cmd/meme$ go get bitbucket.org/anacrolix/meme/cmd/meme
can't load package: /home/matt/gopath/src/bitbucket.org/anacrolix/meme/cmd/meme/main.go:8:2: local import "../../../meme" in non-local package
matt@stanley:~/gopath/src/bitbucket.org/anacrolix/meme/cmd/meme$ echo $GOPATH
/home/matt/gopath
How do I import locally from a parent directory?
答案1
得分: 53
**编辑:**在Go中,相对导入路径不是一个好的选择。缺乏文档说明了相对路径的流行程度,并且我不认为使用它们有什么理由。Go的推荐代码组织方式非常好用。每个包都应该有一个唯一的导入路径,并且在任何地方都使用相同的导入路径进行导入。
看看像github.com/ha/doozerd/peer
这样的包导入它的邻居。这是Go项目中常见的做法,我见过很多次。包camlistore.org/pkg/auth
(也在GitHub上;由Go的主要作者之一编写)通过完整路径导入了camlistore.org/pkg/netutil
。
即使在同一个项目中同时有命令和库,这种方法也适用。在你最初的问题中,你明智地询问了最佳实践。我尽力解释了关于这个问题的最佳实践。
在Go中,导入路径不能是相对的。我建议阅读如何编写Go代码,这是组织Go项目的必读文献。以下是一个简短的概述:
创建一个名为~/go
的目录用于Go开发。然后执行以下命令:
$ export GOPATH=~/go
$ mkdir $GOPATH/{src,bin,pkg}
$GOPATH/src
目录用于存放所有Go包的源代码,甚至包括使用go get
下载的包。bin
和pkg
目录用于存放编译的输出文件。包名为main
的包是命令,编译后生成的可执行文件将放在$GOPATH/bin
目录下。其他包是库,它们的编译后的目标文件将放在$GOPATH/pkg
目录下。
现在,如果你将代码放在$GOPATH/src/matt/meme
目录下,你可以通过import "matt/meme"
来导入它。建议为包名使用前缀,并将短包名留给标准库。这就是为什么我使用了$GOPATH/src/matt/meme
而不是$GOPATH/src/meme
的原因。
围绕这个思想组织你的代码。
英文:
Edit: Relative import paths are not the way to go in Go. Lack of documentation shows something about popularity of relative paths, and I don't see a reason for using them. Go's recommended code organization works pretty well. Every package should have a unique import path and be imported everywhere using that same import path.
See how a package like github.com/ha/doozerd/peer
imports its neighbors. This is a common practice among Go projects and I've seen it a lot of times. Package camlistore.org/pkg/auth
(also on GitHub; written by one of the main authors of Go) imports camlistore.org/pkg/netutil
by full path.
Even if you are having both commands and libraries in the same project this approach works. In your original questions you wisely asked for best practices. I did my best in explaining best practices on this matter.
<hr />
<s>Import paths can't be relative in Go.</s> I recommend reading How to Write Go Code, the essential reading on organizing Go projects. Here's a short overview:
Make a directory like ~/go
for your Go development. Then say:
$ export GOPATH=~/go
$ mkdir $GOPATH/{src,bin,pkg}
$GOPATH/src
holds source code for all your Go packages, even the ones your download with go get
. bin
and pkg
keep output of compilations. Packages with package name main
are commands and yield to executable binaries which go to $GOPATH/bin
. Other packages are libraries and their compiled object files are put in $GOPATH/pkg
.
Now if you put your code in $GOPATH/src/matt/meme
, you can import it by import "matt/meme"
. It's recommended to use a prefix for your package names and leave short package names for standard libraries. That's why I used $GOPATH/src/matt/meme
instead of $GOPATH/src/meme
.
Organize your code around this idea.
答案2
得分: 20
感谢您对问题的补充。首先是答案,然后是一些解释。我通过以下步骤构建了您的代码:
- 使用"go get"命令,就像您之前做的一样。(我忽略了错误消息。)
- 将
main.go
中的导入行设置回"../../../meme",就像您想要的那样。 - (注释掉了一小段包含未使用变量的代码。)
- 然后在meme/cmd/meme目录中,使用
go run main.go
或go build main.go
都可以工作。
我之前在评论中说go install可以工作是错误的,我应该说go build。
然而,关键是go build
单独使用是不起作用的;您必须输入go build main.go
。这是因为go命令不允许“非本地包中的本地导入”。您是对的,规范在这里帮助不大。它含糊其辞地说,“ImportPath的解释取决于实现。”当前的实现行为是通过CL 5787055设置的,随后在Go-nuts上进行了长时间的讨论。
“本地”意味着使用文件系统相对路径指示。显然,以..开头的相对路径是本地的,所以关键就是让go
命令也将main视为本地包。显然,当您输入go build
时,它似乎不这样做,但是当您输入go build main.go
时,它会这样做。
英文:
Thanks for adding to your question. First, an answer, then some explanation. I built your code by,
- go get, just as you had it. (I ignored the error messages.)
- setting the import line in
main.go
back to "../../../meme", as you wanted to do. - (commenting out a little bit of code containing an unused variable.)
- then in the meme/cmd/meme directory, either
go run main.go
orgo build main.go
worked.
I was wrong in my comment earlier when I said go install works; I should have said go build.
The key however is that go build
alone does not work; you must type go build main.go
. This is because the go command does not allow "local imports in non-local packages." You are right that spec is of little help here. It weasels out saying, "The interpretation of the ImportPath is implementation-dependent." The current implementation behavior was set with CL 5787055, which was subsequently debated at length on Go-nuts.
"Local" means indicated with a file system relative path. Obviously a relative path starting with .. is local, so the trick is just getting the go
command to treat main as a local package as well. It apparently doesn't do this when you type go build
, but does when you type go build main.go
.
答案3
得分: 3
相对导入在手动使用编译器、链接器等时是被支持的。而"go"(构建)工具不支持相同的功能(与Java类似)。
英文:
Relarive imports are supported when manually using the compiler, linker, ... directly. The 'go' (build) tool doesn't support the same (somehow comparable to eg Java).
答案4
得分: 2
这可能不能回答原始问题,但当我实际上不需要时,我试图做上面的事情,我只需要暂时更新go.mod
文件,使用replace
关键字:
module github.com/pselle/foo
replace github.com/pselle/bar => /Users/pselle/Projects/bar
require (
github.com/pselle/bar v1.0.0
)
参考链接:
https://thewebivore.com/using-replace-in-go-mod-to-point-to-your-local-module/
英文:
This may not answer the original question, but I was trying to do the above when I didn't really need to, all I needed to do was update go.mod
temporarily with a replace
:
module github.com/pselle/foo
replace github.com/pselle/bar => /Users/pselle/Projects/bar
require (
github.com/pselle/bar v1.0.0
)
reference:
https://thewebivore.com/using-replace-in-go-mod-to-point-to-your-local-module/
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论