从父目录进行相对导入

huangapple go评论82阅读模式
英文:

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下载的包。binpkg目录用于存放编译的输出文件。包名为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 &quot;matt/meme&quot;. 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

感谢您对问题的补充。首先是答案,然后是一些解释。我通过以下步骤构建了您的代码:

  1. 使用"go get"命令,就像您之前做的一样。(我忽略了错误消息。)
  2. main.go中的导入行设置回"../../../meme",就像您想要的那样。
  3. (注释掉了一小段包含未使用变量的代码。)
  4. 然后在meme/cmd/meme目录中,使用go run main.gogo 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,

  1. go get, just as you had it. (I ignored the error messages.)
  2. setting the import line in main.go back to "../../../meme", as you wanted to do.
  3. (commenting out a little bit of code containing an unused variable.)
  4. then in the meme/cmd/meme directory, either go run main.go or go 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 =&gt; /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/

huangapple
  • 本文由 发表于 2012年5月21日 22:53:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/10687627.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定