Go包名规则

每个.go模块文件,开头的package名称和文件名是什么关系?
import的时候,路径、文件名和包名又是什么关系?

Go源码的做法

来看看系统怎么做的:

1
2
3
4
5
6
7
$ cd %GOROOT%/src/fmt
$ tree .
.
├── format.go
├── print.go
├── scan.go
└── ...

这三个文件开头均为:

1
2
package fmt
...

于是可以推测

import XXX时,编译器会查找%GOROOT%/src/XXX(其次再找%GOPATH/src/XXX)下以package XXX开头的所有go文件,并找到被引用的元素,完成编译。因此,文件名其实是无所谓的

如果包名和路径名不一致呢

1
2
3
4
5
6
7
8
$ cd %GOPAT%/src/test
$ tree .
.
├── test.go
├── pkgA
│ └── model.go # 以 package model 开头
└── pkgB
└── model.go # 以 package model 开头

这种情况下test.go应该如何引用pkgA/model.go中的模块呢?如下:

1
2
3
4
5
import model "test/pkgA"

func main(){
model.Func()
}

也就是说

import语句可以包含包名包路径,如果省略包名,则其默认值和导入目录下的文件所声明的包名一致。这就要求一个目录下的所有文件只能定义一个包名。

如果一个目录下包含的多个文件声明了多个包名呢?对不起,编译报错!

1
2
3
4
5
6
7
8
$ cd %GOPAT%/src/test
$ tree .
.
├── test.go
├── pkgA
│ ├── model1.go # 以 package model1 开头
│ └── model2.go # 以 package model2 开头
└── ...

会报出如下错误:

1
found packages model1 (model1.go) and model2 (model2.go) in XXX/pkgA(undefined)

也就是说:

import 包名 包路径中的包名并非指定要导入的包名,因为只要包路径确定了,包名就确定了。这个包名其实是给导入的包名指定一个别名。

如果不同目录定义了同名包名呢?

如下所示:

1
2
3
4
5
6
7
8
$ cd %GOPAT%/src/test
$ tree .
.
├── test.go
├── pkgA
│ └── model.go # 以 package model 开头
└── pkgB
└── model.go # 以 package model 开头

test.go在使用pkgApkgB时,应如下书写:

1
2
3
4
5
6
7
import modelA "test/pkgA"
import modelB "test/pkgB"

func main(){
modelA.Func()
modelB.Func()
}

官方文档的说法

Go 语言规范官方文档中有对PackageNameImportPath的具体描述:

1
2
3
ImportDecl       = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
ImportSpec = [ "." | PackageName ] ImportPath .
ImportPath = string_lit .

The PackageName is used in qualified identifiers to access exported identifiers of the package within the importing source file. It is declared in the file block. If the PackageName is omitted, it defaults to the identifier specified in the package clause of the imported package. If an explicit period (.) appears instead of a name, all the package’s exported identifiers declared in that package’s package block will be declared in the importing source file’s file block and must be accessed without a qualifier.