Golang: Command: Import Path

 13th January 2022 at 4:11pm

很多 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 package

特殊名称

有一些特殊的 import path 名称,

  • main, std:比较少见,不讨论
  • allgo 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

References