很多 go 命令执行时都是这样的形态:
go action [pacakges]
比如:
go build ./app/worker
go test ./...
go list all
其中 packages 是一批 import path。
Import path
import path 有好几种:
- 如果是
/
.
..
开头,表示某个本地目录路径下的包;否则, - 如果用
P
代表传入的 import path,并且:- 没有启用 go mod,则 go 会尝试去
$GOPATH/src/P
下找该包 - 启用了 go mod:
- 该包不在
go.mod
文件中被 require,会报错; - 该包在
go.mod
文件中被 require,即使本地 cache 还没有此包,go 也会自动下载该包
- 该包不在
- 没有启用 go mod,则 go 会尝试去
- 如果是空的,表示当前目录下的 go package
特殊名称
有一些特殊的 import path 名称,
- main, std:比较少见,不讨论
- all:
go list all
时,表示 main module 以及 go.mod 定义的所有依赖及其子依赖 - cmd:表示 Go 自己的命令。
cmd/
开头的都指向 Go 自己的 cmd 包- 你自己的项目也可以用
cmd
目录;只是使用时 import path 应该以./cmd/
打头
- 你自己的项目也可以用
...
pattern
...
是一种特殊 wildcards pattern,表示匹配空白或任意字符串。因此:
./...
表示匹配当前目录及所有子目录net/...
表示匹配net
目录(当然,是$GOPATH
下的)及所有子目录
Go 会在这些目录中尝试找 package。但有一些例外:
- vendor 目录及其子目录会被忽略(除非 vendor 目录下直接有 go 文件,但这种情况我没见过)
.
,_
开头的,或者名为testdata
的文件和目录,会被忽略
Special cases
一个 .go
文件可以在其文件头定义它所在的包:
package readers
func SomeFunc() {
// ...
}
一般来讲,这种形式定义的 package 是可以被别的 go 文件 import 并使用的。但是有一些例外:
package main
:表示这个 go 文件是用来生成可执行的二进制文件的。其中定义的符号无法被其他包引用。package documentation
:表示一个非 go 程序的文档。我没有见过这种例子。
Very special case
假如 go action [pacakges]
中传的 package 参数是一批同一目录的 go 文件,go 命令会认为这批文件合成了一个临时的 package,并且忽略它们所在目录的其他文件。
Error cases
有一个常见的小 case。对于这样的目录结构:
$ tree .
.
├── d1
│ └── main.go
├── go.mod
└── go.sum
构建时:
$ tree .
$ go build ./d1
go build: build output "d1" already exists and is a directory
这是因为按规则,go build
生成的 binary 也叫 d1
,但是 d1
名字已经被 d1/
目录占用了。可以为 binary 指定一个其他的名字:
$ go build -o main ./d1