当前位置: 首页 > 文档资料 > Go 命令教程 >

go list

优质
小牛编辑
129浏览
2023-12-01

go list命令的作用是列出指定的代码包的信息。与其他命令相同,我们需要以代码包导入路径的方式给定代码包。被给定的代码包可以有多个。这些代码包对应的目录中必须直接保存有Go语言源码文件,其子目录中的文件不算在内。否则,代码包将被看做是不完整的。现在我们来试用一下:

hc@ubt:~$ go list cnet/ctcp pkgtool
cnet/ctcp
pkgtool

我们看到,在不加任何标记的情况下,命令的结果信息中只包含了我们指定的代码包的导入路径。我们刚刚提到,作为参数的代码包必须是完整的代码包。例如:

hc@ubt:~$ go list cnet pkgtool
can't load package: package cnet: no buildable Go source files in /home/hc/golang/goc2p/src/cnet/
pkgtool

这时,go list命令报告了一个错误——代码包cnet对应的目录下没有Go源码文件。但是命令还是把代码包pkgtool的导入路径打印出来了。然而,当我们在执行go list命令并加入标记-e时,即使参数中包含有不完整的代码包,命令也不会提示错误。示例如下:

hc@ubt:~$ go list -e cnet pkgtool
cnet
pkgtool

标记-e的作用是以容错模式加载和分析指定的代码包。在这种情况下,命令程序如果在加载或分析的过程中遇到错误只会在内部记录一下,而不会直接把错误信息打印出来。我们为了看到错误信息可以使用-json标记。这个标记的作用是把代码包的结构体实例用JSON的样式打印出来。

这里解释一下,JSON的全称是Javascript Object Notation。它一种轻量级的承载数据的格式。JSON的优势在于语法简单、短小精悍,且非常易于处理。JSON还是一种纯文本格式,独立于编程语言。正因为如此,得到了绝大多数编程语言和浏览器的支持,应用非常广泛。Go语言当然也不例外,在它的标准库中有专门用于处理和转换JSON格式的数据的代码包encoding/json。关于JSON格式的具体内容,读者可以去它的官方网站查看说明。

在了解了这些基本概念之后,我们来试用一下-json标记。示例如下:

hc@ubt:~$ go list -e -json cnet
    {
            "Dir": "/home/hc/golang/goc2p/src/cnet",
            "ImportPath": "cnet",
            "Stale": true,
            "Root": "/home/hc/golang/goc2p",
            "Incomplete": true,
            "Error": {
                    "ImportStack": [
                            "cnet"
                    ],
                    "Pos": "",
                    "Err": "no Go source files in /home/hc/golang/goc2p/src/cnet"
            }
    }

在上述JSON格式的代码包信息中,对于结构体中的字段的显示是不完整的。因为命令程序认为我们指定cnet就是不完整的。在名为Error的字段中,我们可以看到具体说明。Error字段的内容其实也是一个结构体。在JSON格式下,这种嵌套的结构体被完美的展现了出来。Error字段所指代的结构体实例的Err字段说明了cnet不完整的原因。这与我们在没有使用-e标记的情况下所打印出来的错误提示信息是一致的。我们再来看Incomplete字段。它的值为true。这同样说明cnet是一个不完整的代码包。

实际上,在从这个代码包结构体实例到JSON格式文本的转换过程中,所有的值为其类型的空值的字段都已经被忽略了。

现在我们使用带-json标记的go list命令列出代码包cnet/ctcp的信息:

hc@ubt:~$ go list -json cnet/ctcp
{
    "Dir": "/home/hc/golang/github/goc2p/src/cnet/ctcp",
    "ImportPath": "cnet/ctcp",
    "Name": "ctcp",
    "Target": "/home/hc/golang/github/goc2p/pkg/darwin_amd64/cnet/ctcp.a",
    "Stale": true,
    "Root": "/home/hc/golang/github/goc2p",
    "GoFiles": [
        "base.go",
        "tcp.go"
    ],
    "Imports": [
        "bufio",
        "bytes",
        "errors",
        "logging",
        "net",
        "sync",
        "time"
    ],
    "Deps": [
        "bufio",
        "bytes",
        "errors",
        "fmt",
        "internal/singleflight",
        "io",
        "log",
        "logging",
        "math",
        "math/rand",
        "net",
        "os",
        "reflect",
        "runtime",
        "runtime/cgo",
        "sort",
        "strconv",
        "strings",
        "sync",
        "sync/atomic",
        "syscall",
        "time",
        "unicode",
        "unicode/utf8",
        "unsafe"
    ],
    "TestGoFiles": [
        "tcp_test.go"
    ],
    "TestImports": [
        "bytes",
        "fmt",
        "net",
        "runtime",
        "strings",
        "sync",
        "testing",
        "time"
    ]
}

由于cnet/ctcp包是一个完整有效的代码包,所以我们不使用-e标记也是没有问题的。在上面打印的cnet/ctcp包的信息中没有Incomplete字段。这是因为完整的代码包中的Incomplete字段的其类型的空值false。它已经在转换过程中被忽略掉了。另外,在cnet/ctcp包的信息中我们看到了很多其它的字段。现在我就来看看在Go命令程序中的代码包结构体都有哪些公开的字段。如下表。

表0-7 代码包结构体中的基本字段

字段名称字段类型字段描述
Dir字符串(string)代码包对应的目录。
ImportPath字符串(string)代码包的导入路径。
ImportComment字符串(string)代码包声明语句右边的用于自定义导入路径的注释。
Name字符串(string)代码包的名称。
Doc字符串(string)代码包的文档字符串。
Target字符串(string)代码包的安装路径。
Shlib字符串(string)包含该代码包的共享库(shared library)的名称。
Goroot布尔(bool)该代码包是否在Go语言安装目录下。
Standard布尔(bool)该代码包是否属于标准库的一部分。
Stale布尔(bool)该代码包的最新代码是否未被安装。
Root字符串(string)该代码包所属的工作区或Go安装目录的路径。

表0-8 代码包结构体中与源码文件有关的字段

字段名称字段类型字段描述
GoFiles字符串切片([]string)Go源码文件的列表。不包含导入了代码包“C”的源码文件和测试源码文件。
CgoFiles字符串切片([]string)导入了代码包“C”的源码文件的列表。
IgnoredGoFiles字符串切片([]string)忽略编译的源码文件的列表。
CFiles字符串切片([]string)名称中有“.c”后缀的源码文件的列表。
CXXFiles字符串切片([]string)名称中有“.cc”、“.cxx”或“.cpp”后缀的源码文件的列表。
MFiles字符串切片([]string)名称中“.m”后缀的源码文件的列表。
HFiles字符串切片([]string)名称中有“.h”后缀的源码文件的列表。
SFiles字符串切片([]string)名称中有“.s”后缀的源码文件的列表。
SwigFiles字符串切片([]string)名称中有“.swig”后缀的文件的列表。
SwigCXXFiles字符串切片([]string)名称中有“.swigcxx”后缀的文件的列表。
SysoFiles字符串切片([]string)名称中有“.syso”后缀的文件的列表。这些文件是需要被加入到归档文件中的。

表0-9 代码包结构体中与Cgo指令有关的字段

字段名称字段类型字段描述
CgoCFLAGS字符串切片([]string)需要传递给C编译器的标记的列表。针对Cgo。
CgoCPPFLAGS字符串切片([]string)需要传递给C预处理器的标记的列表。针对Cgo。
CgoCXXFLAGS字符串切片([]string)需要传递给C++编译器的标记的列表。针对Cgo。
CgoLDFLAGS字符串切片([]string)需要传递给链接器的标记的列表。针对Cgo。
CgoPkgConfig字符串切片([]string)pkg-config的名称的列表。针对Cgo。

表0-10 代码包结构体中与依赖信息有关的字段

字段名称字段类型字段描述
Imports字符串切片([]string)该代码包中的源码文件显式导入的依赖包的导入路径的列表。
Deps字符串切片([]string)所有的依赖包(包括间接依赖)的导入路径的列表。

表0-11 代码包结构体中与错误信息有关的字段

字段名称字段类型字段描述
Incomplete布尔(bool)代码包是否是完整的,也即在载入或分析代码包及其依赖包时是否有错误发生。
Error*PackageError类型载入或分析代码包时发生的错误。
DepsErrors[]*PackageError类型载入或分析依赖包时发生的错误。

表0-12 代码包结构体中与测试源码文件有关的字段

字段名称字段类型字段描述
TestGoFiles字符串切片([]string)代码包中的测试源码文件的名称列表。
TestImports字符串切片([]string)代码包中的测试源码文件显示导入的依赖包的导入路径的列表。
XTestGoFiles字符串切片([]string)代码包中的外部测试源码文件的名称列表。
XTestImports字符串切片([]string)代码包中的外部测试源码文件显示导入的依赖包的导入路径的列表。

代码包结构体中定义的字段很多,但有些时候我们只需要查看其中的一些字段。那要怎么做呢?标记-f可以满足这个需求。比如这样:

hc@ubt:~$ go list -f {{.ImportPath}} cnet/ctcp
cnet/ctcp

实际上,-f标记的默认值就是{{.ImportPath}}。这也正是我们在使用不加任何标记的go list命令时依然能看到指定代码包的导入路径的原因了。

标记-f的值需要满足标准库的代码包`text/template中定义的语法。比如,{{.S}}代表根结构体的S字段的值。在go list命令的场景下,这个根结构体就是指定的代码包所对应的结构体。如果S字段的值也是一个结构体的话,那么{{.S.F}}就代表根结构体的S字段的值中的F字段的值。如果我们要查看cnet/ctcp包中的命令源码文件和库源码文件的列表,可以这样使用-f标记:

hc@ubt:~$ go list -f {{.GoFiles}} cnet/ctcp
[base.go tcp.go]

如果我们想查看不完整的代码包cnet的错误提示信息,还可以这样:

hc@ubt:~$ go list -e -f {{.Error.Err}} cnet
no buildable Go source files in /home/hc/golang/goc2p/src/cnet

我们还可以利用代码包text/template中定义的强大语法让go list命令输出定制化更高的代码包信息。比如:

hc@ubt:~$ go list -e -f 'The package {{.ImportPath}} is {{if .Incomplete}}incomplete!{{else}}complete.{{end}}' cnet
The package cnet is incomplete!

```bash 
hc@ubt:~$ go list -f 'The imports of package {{.ImportPath}} is [{{join .Imports ", "}}].' cnet/ctcp
The imports of package cnet/ctcp is [bufio, bytes, errors, logging, net, sync, time].

其中,join是命令程序在text/template包原有语法之上自定义的语法,在底层使用标准库代码包strings中的Join函数。关于更多的语法规则,请读者查看代码包text/template的相关文档。

另外,-tags标记也可以被go list接受。它与我们在讲go build命令时提到的-tags标记是一致的。读者可以查看代码包`go/build``的文档以了解细节。

go list命令很有用。它可以为我们提供指定代码包的更深层次的信息。这些信息往往是我们无法从源码文件中直观看到的。