go list
命令的作用是列出指定的代碼包的信息。與其他命令相同,我們需要以代碼包導(dǎo)入路徑的方式給定代碼包。被給定的代碼包可以有多個。這些代碼包對應(yīng)的目錄中必須直接保存有Go語言源碼文件,其子目錄中的文件不算在內(nèi)。否則,代碼包將被看做是不完整的?,F(xiàn)在我們來試用一下:
hc@ubt:~$ go list cnet/ctcp pkgtool
cnet/ctcp
pkgtool
我們看到,在不加任何標(biāo)記的情況下,命令的結(jié)果信息中只包含了我們指定的代碼包的導(dǎo)入路徑。我們剛剛提到,作為參數(shù)的代碼包必須是完整的代碼包。例如:
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
對應(yīng)的目錄下沒有Go源碼文件。但是命令還是把代碼包pkgtool的導(dǎo)入路徑打印出來了。然而,當(dāng)我們在執(zhí)行go list
命令并加入標(biāo)記-e
時,即使參數(shù)中包含有不完整的代碼包,命令也不會提示錯誤。示例如下:
hc@ubt:~$ go list -e cnet pkgtool
cnet
pkgtool
標(biāo)記-e
的作用是以容錯模式加載和分析指定的代碼包。在這種情況下,命令程序如果在加載或分析的過程中遇到錯誤只會在內(nèi)部記錄一下,而不會直接把錯誤信息打印出來。我們?yōu)榱丝吹藉e誤信息可以使用-json
標(biāo)記。這個標(biāo)記的作用是把代碼包的結(jié)構(gòu)體實例用JSON的樣式打印出來。
這里解釋一下,JSON的全稱是Javascript Object Notation。它一種輕量級的承載數(shù)據(jù)的格式。JSON的優(yōu)勢在于語法簡單、短小精悍,且非常易于處理。JSON還是一種純文本格式,獨立于編程語言。正因為如此,得到了絕大多數(shù)編程語言和瀏覽器的支持,應(yīng)用非常廣泛。Go語言當(dāng)然也不例外,在它的標(biāo)準(zhǔn)庫中有專門用于處理和轉(zhuǎn)換JSON格式的數(shù)據(jù)的代碼包encoding/json
。關(guān)于JSON格式的具體內(nèi)容,讀者可以去它的官方網(wǎng)站查看說明。
在了解了這些基本概念之后,我們來試用一下-json
標(biāo)記。示例如下:
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格式的代碼包信息中,對于結(jié)構(gòu)體中的字段的顯示是不完整的。因為命令程序認(rèn)為我們指定cnet
就是不完整的。在名為Error
的字段中,我們可以看到具體說明。Error
字段的內(nèi)容其實也是一個結(jié)構(gòu)體。在JSON格式下,這種嵌套的結(jié)構(gòu)體被完美的展現(xiàn)了出來。Error
字段所指代的結(jié)構(gòu)體實例的Err
字段說明了cnet
不完整的原因。這與我們在沒有使用-e
標(biāo)記的情況下所打印出來的錯誤提示信息是一致的。我們再來看Incomplete
字段。它的值為true
。這同樣說明cnet
是一個不完整的代碼包。
實際上,在從這個代碼包結(jié)構(gòu)體實例到JSON格式文本的轉(zhuǎn)換過程中,所有的值為其類型的空值的字段都已經(jīng)被忽略了。
現(xiàn)在我們使用帶-json
標(biāo)記的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
標(biāo)記也是沒有問題的。在上面打印的cnet/ctcp
包的信息中沒有Incomplete
字段。這是因為完整的代碼包中的Incomplete
字段的其類型的空值false
。它已經(jīng)在轉(zhuǎn)換過程中被忽略掉了。另外,在cnet/ctcp
包的信息中我們看到了很多其它的字段?,F(xiàn)在我就來看看在Go命令程序中的代碼包結(jié)構(gòu)體都有哪些公開的字段。如下表。
表0-7 代碼包結(jié)構(gòu)體中的基本字段
字段名稱 | 字段類型 | 字段描述 |
---|---|---|
Dir | 字符串(string) | 代碼包對應(yīng)的目錄。 |
ImportPath | 字符串(string) | 代碼包的導(dǎo)入路徑。 |
ImportComment | 字符串(string) | 代碼包聲明語句右邊的用于自定義導(dǎo)入路徑的注釋。 |
Name | 字符串(string) | 代碼包的名稱。 |
Doc | 字符串(string) | 代碼包的文檔字符串。 |
Target | 字符串(string) | 代碼包的安裝路徑。 |
Shlib | 字符串(string) | 包含該代碼包的共享庫(shared library)的名稱。 |
Goroot | 布爾(bool) | 該代碼包是否在Go語言安裝目錄下。 |
Standard | 布爾(bool) | 該代碼包是否屬于標(biāo)準(zhǔn)庫的一部分。 |
Stale | 布爾(bool) | 該代碼包的最新代碼是否未被安裝。 |
Root | 字符串(string) | 該代碼包所屬的工作區(qū)或Go安裝目錄的路徑。 |
表0-8 代碼包結(jié)構(gòu)體中與源碼文件有關(guān)的字段
字段名稱 | 字段類型 | 字段描述 |
---|---|---|
GoFiles | 字符串切片([]string) | Go源碼文件的列表。不包含導(dǎo)入了代碼包“C”的源碼文件和測試源碼文件。 |
CgoFiles | 字符串切片([]string) | 導(dǎo)入了代碼包“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 代碼包結(jié)構(gòu)體中與Cgo指令有關(guān)的字段
字段名稱 | 字段類型 | 字段描述 |
---|---|---|
CgoCFLAGS | 字符串切片([]string) | 需要傳遞給C編譯器的標(biāo)記的列表。針對Cgo。 |
CgoCPPFLAGS | 字符串切片([]string) | 需要傳遞給C預(yù)處理器的標(biāo)記的列表。針對Cgo。 |
CgoCXXFLAGS | 字符串切片([]string) | 需要傳遞給C++編譯器的標(biāo)記的列表。針對Cgo。 |
CgoLDFLAGS | 字符串切片([]string) | 需要傳遞給鏈接器的標(biāo)記的列表。針對Cgo。 |
CgoPkgConfig | 字符串切片([]string) | pkg-config的名稱的列表。針對Cgo。 |
表0-10 代碼包結(jié)構(gòu)體中與依賴信息有關(guān)的字段
字段名稱 | 字段類型 | 字段描述 |
---|---|---|
Imports | 字符串切片([]string) | 該代碼包中的源碼文件顯式導(dǎo)入的依賴包的導(dǎo)入路徑的列表。 |
Deps | 字符串切片([]string) | 所有的依賴包(包括間接依賴)的導(dǎo)入路徑的列表。 |
表0-11 代碼包結(jié)構(gòu)體中與錯誤信息有關(guān)的字段
字段名稱 | 字段類型 | 字段描述 |
---|---|---|
Incomplete | 布爾(bool) | 代碼包是否是完整的,也即在載入或分析代碼包及其依賴包時是否有錯誤發(fā)生。 |
Error | *PackageError類型 | 載入或分析代碼包時發(fā)生的錯誤。 |
DepsErrors | []*PackageError類型 | 載入或分析依賴包時發(fā)生的錯誤。 |
表0-12 代碼包結(jié)構(gòu)體中與測試源碼文件有關(guān)的字段
字段名稱 | 字段類型 | 字段描述 |
---|---|---|
TestGoFiles | 字符串切片([]string) | 代碼包中的測試源碼文件的名稱列表。 |
TestImports | 字符串切片([]string) | 代碼包中的測試源碼文件顯示導(dǎo)入的依賴包的導(dǎo)入路徑的列表。 |
XTestGoFiles | 字符串切片([]string) | 代碼包中的外部測試源碼文件的名稱列表。 |
XTestImports | 字符串切片([]string) | 代碼包中的外部測試源碼文件顯示導(dǎo)入的依賴包的導(dǎo)入路徑的列表。 |
代碼包結(jié)構(gòu)體中定義的字段很多,但有些時候我們只需要查看其中的一些字段。那要怎么做呢?標(biāo)記-f
可以滿足這個需求。比如這樣:
hc@ubt:~$ go list -f {{.ImportPath}} cnet/ctcp
cnet/ctcp
實際上,-f
標(biāo)記的默認(rèn)值就是{{.ImportPath}}
。這也正是我們在使用不加任何標(biāo)記的go list
命令時依然能看到指定代碼包的導(dǎo)入路徑的原因了。
標(biāo)記-f
的值需要滿足標(biāo)準(zhǔn)庫的代碼包`text/template
中定義的語法。比如,{{.S}}
代表根結(jié)構(gòu)體的S
字段的值。在go list
命令的場景下,這個根結(jié)構(gòu)體就是指定的代碼包所對應(yīng)的結(jié)構(gòu)體。如果S
字段的值也是一個結(jié)構(gòu)體的話,那么{{.S.F}}
就代表根結(jié)構(gòu)體的S
字段的值中的F
字段的值。如果我們要查看cnet/ctcp
包中的命令源碼文件和庫源碼文件的列表,可以這樣使用-f
標(biāo)記:
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
包原有語法之上自定義的語法,在底層使用標(biāo)準(zhǔn)庫代碼包strings
中的Join
函數(shù)。關(guān)于更多的語法規(guī)則,請讀者查看代碼包text/template
的相關(guān)文檔。
另外,-tags
標(biāo)記也可以被go list
接受。它與我們在講go build
命令時提到的-tags
標(biāo)記是一致的。讀者可以查看代碼包`go/build``的文檔以了解細節(jié)。
go list
命令很有用。它可以為我們提供指定代碼包的更深層次的信息。這些信息往往是我們無法從源碼文件中直觀看到的。