参见此实验。
~/go/src$ tree -F
.
├── 1-foodir/
│ └── 2-foofile.go
└── demo.go
1 directory, 2 files
~/go/src$ cat demo.go
package main
import (
"fmt"
"1-foodir"
)
func main() {
fmt.Println(foopkg.FooFunc())
}
~/go/src$ cat 1-foodir/2-foofile.go
package foopkg
func FooFunc() string {
return "FooFunc"
}
~/go/src$ GOPATH=~/go go run demo.go
FooFunc
我以为我们总是导入一个包名。但是上面的例子
表明我们实际导入了一个包目录名("1-foodir"
)
但是在调用该包中的导出名称时,我们使用了
在Go文件(foopkg.FooFunc
)中声明的包名称。
这对像我这样来自Java和Python世界的初学者来说很困惑, 目录名称本身就是用于限定的包名称 包中定义的模块/类。
为什么我们使用import
语句的方式有所不同
参考Go中包中定义的名称?你能解释一下规则吗?
关于Go的这些事情背后?
答案 0 :(得分:4)
如果你说的是真的,那么你的函数调用实际上是1 - foodir.FooFunc()
而不是foopkg.FooFunc()
。相反,go在2-foofile.go中看到包名称并将其导入为foopkg
,因为在包中,包名称正好是.go文件顶部的单词package
之后的名称,只要它是有效的标识符。
目录的唯一用途是收集共享相同包名的一组文件。这在规范中重申了
一组共享相同PackageName的文件形成包的实现。实现可能要求包的所有源文件都位于同一目录中。
在go中,通常目录与包名匹配,但这不是必须的,并且通常不包含第三方包。 stdlib确实很好地坚持了这个惯例。
目前做的目录是导入路径。您可以拥有两个名为' foo'在你的单个二进制文件中,只要它们有不同的导入路径,即
/some/path/1/foo
和/some/path/2/foo
我们可以变得非常时髦,并将进口别名变为我们想要的任何东西,例如我可以做到
import (
bar "/some/path/1/foo"
baz "/some/path/2/foo"
)
同样有效的原因不是因为包名必须是唯一的,而且包导入路径必须是唯一的。
从这个陈述中收集的另一个洞察力是 - 在一个目录中,你不能有两个包名。 go编译器会抛出一个错误,说明它cannot load package
并且它found packages foo (foo.go) and bar (bar.go)
。
答案 1 :(得分:3)
大致为什么:
套餐有一个"名称"这是由package子句设置的,源代码开头是package thepackagename
。
导入包的过程几乎是不透明的字符串:导入声明中的导入路径。
第一个是名称,第二个是如何找到该名称。第一个是程序员,第二个是编译器/工具链。 声明(编译器和程序员)非常方便
请导入
中找到的包"/some/hierarchical/location"
然后在
等语句中通过它的简单名称robot
引用该包
robot.MoveTo(3,7)
请注意使用此包
/some/hierarchical/location.MoveTo(3.7)
不是合法代码,既不可读也不清晰也不方便。 但是对于编译器/工具链,如果导入路径具有结构并允许表示任意包位置,即不仅是文件系统中的位置,而且例如,在档案馆内或远程机器上,或或。或。
同样重要的是要注意:Go编译器和go
工具。 Go编译器和go工具是不同的东西,go工具对你的代码,工作空间和包的布局方式施加了比Go编译器和语言规范所要求的更多限制。 (例如,Go编译器允许将来自不同目录的文件编译成一个包而没有任何问题。)
go
工具强制要求所有(有特殊情况,我知道)包的源文件驻留在一个文件系统目录中,并且常识要求此目录应该被命名为包"
答案 2 :(得分:1)
首先,包子句和导入路径是不同的东西。
package clause 声明 PackageName
:
PackageClause = "package" PackageName .
PackageName = identifier .
包子句的目的是对文件进行分组:
<块引用>一组共享相同 PackageName 的文件构成了一个包的实现。
按照惯例,ImportPath
(见下文)的路径基名(目录名)与 PackageName
相同。为方便起见,建议您无需考虑要使用的 PackageName
。
但是,它们可以不同。
basename 只影响 ImportPath
,检查 spec for import declartions:
ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
ImportSpec = [ "." | PackageName ] ImportPath .
ImportPath = string_lit .
<块引用>
如果省略 PackageName,则默认为导入包的 package 子句中指定的标识符。
例如,如果您有一个目录 foo
,但您声明 package bar
位于其中的源文件中,那么当您 import <prefix>/foo
时,您将使用 bar
作为前缀以引用从该包中导出的任何符号。
darehas' answer 提出了一个很好的观点:您不能在同一个基本名称下声明多个包。但是,根据 package clause,您可以将相同的包分布在不同的基名上:
<块引用>实现可能要求包的所有源文件都位于同一目录中。