一、Go的源碼文件
Go 的源碼文件分類:

如上圖,分為三類:
1、命令源碼文件:
聲明自己屬于 main 代碼包、包含無參數聲明和結果聲明的 main 函數。
命令源碼文件被安裝以后,GOPATH 如果只有一個工作區(qū),那么相應的可執(zhí)行文件會被存放當前工作區(qū)的 bin 文件夾下;如果有多個工作區(qū),就會安裝到 GOBIN 指向的目錄下。
命令源碼文件是 Go 程序的入口。
同一個代碼包中最好也不要放多個命令源碼文件。多個命令源碼文件雖然可以分開單獨 go run 運行起來,但是無法通過 go build 和 go install。
我們先打開上次課的hello目錄,然后復制helloworld.go為helloworld2.go文件,并修改里面的內容:
packagemain
import"fmt"
funcmain(){
? ? fmt.Println("我是第二個helloworld文件")
? ? fmt.Print("Go Go Go !!!")
}
hello目錄下有兩個go文件了,一個是helloworld.go,一個是helloworld2.go。先說明一下,在上述文件夾中放了兩個命令源碼文件,同時都聲明自己屬于 main 代碼包。

打開終端,進入hello這個目錄,也可以看到這兩個文件:
localhost:~ rubycdgo/src/hello
localhost:hello rubyls
helloworld.go? helloworld2.go
然后我們分別執(zhí)行go run命令,可以看到兩個go文件都可以被執(zhí)行:
localhost:hello ruby$ gorun helloworld.go
HelloWorld
Go Go Go !!!localhost:hello ruby$ gorun helloworld2.go
我是第二個helloworld文件
Go Go Go !!!

接下來執(zhí)行 go build 和 go install ,看看會發(fā)生什么:
localhost:hello ruby$ gobuild
# hello
./helloworld2.go:3:6: main redeclaredinthis block
? ? previous declaration at ./helloworld.go:3:6
localhost:hello ruby$ goinstall
# hello
./helloworld2.go:3:6: main redeclaredinthis block
? ? previous declaration at ./helloworld.go:3:6
localhost:hello ruby$
運行效果圖:

這也就證明了多個命令源碼文件雖然可以分開單獨 go run 運行起來,但是無法通過 go build 和 go install。
同理,如果命令源碼文件和庫源碼文件也會出現這樣的問題,庫源碼文件不能通過 go build 和 go install 這種常規(guī)的方法編譯和安裝。具體例子和上述類似,這里就不再貼代碼了。
所以命令源碼文件應該是被單獨放在一個代碼包中。
2、庫源碼文件
庫源碼文件就是不具備命令源碼文件上述兩個特征的源碼文件。存在于某個代碼包中的普通的源碼文件。
庫源碼文件被安裝后,相應的歸檔文件(.a 文件)會被存放到當前工作區(qū)的 pkg 的平臺相關目錄下。
3、測試源碼文件
名稱以 _test.go 為后綴的代碼文件,并且必須包含 Test 或者 Benchmark 名稱前綴的函數:
funcTestXXX(t*testing.T) {
?
}
名稱以 Test 為名稱前綴的函數,只能接受 *testing.T 的參數,這種測試函數是功能測試函數。
funcBenchmarkXXX(b*testing.B) {
?
}
?
名稱以 Benchmark 為名稱前綴的函數,只能接受 *testing.B 的參數,這種測試函數是性能測試函數。
現在答案就很明顯了:
命令源碼文件是可以單獨運行的??梢允褂?go run 命令直接運行,也可以通過 go build 或 go install 命令得到相應的可執(zhí)行文件。所以命令源碼文件是可以在機器的任何目錄下運行的。
舉個栗子:
比如平時我們在 LeetCode 上刷算法題,這時候寫的就是一個程序,這就是命令源碼文件,可以在電腦的任意一個文件夾新建一個 go 文件就可以開始刷題了,寫完就可以運行,對比執(zhí)行結果,答案對了就可以提交代碼。
但是公司項目里面的代碼就不能這樣了,只能存放在 GOPATH 目錄下。因為公司項目不可能只有命令源碼文件的,肯定是包含庫源碼文件,甚至包含測試源碼文件的。
二、Go的命令
目前Go的最新版1.12里面基本命令有以下17個。
我們可以打開終端輸入:go help即可看到Go的這些命令以及簡介。
? ? bugstarta bug report
? ? build ? ? ? compile packages and dependencies
? ? clean ? ? ? remove object files and cached files
? ? doc ? ? ? ? show documentationforpackage or symbol
? ? env ? ? ? ? print Go environment information
? ? fix ? ? ? ? update packages to use new APIs
? ? fmt ? ? ? ? gofmt (reformat) package sources
? ? generate ?? generate Go files by processingsource
? ? getdownload and install packages and dependencies
? ? install ? ? compile and install packages and dependencies
? ? list ? ? ?? list packages or modules
? ? mod ? ? ? ? module maintenance
? ? run ? ? ? ? compile and run Go program
? ? test ? ? ?? test packages
? ? tool ? ? ?? run specified go tool
? ? version ? ? print Go version
? ? vet ? ? ? ? report likely mistakesinpackages
其中和編譯相關的有build、get、install、run這4個。接下來就依次看看這四個的作用。
在詳細分析這4個命令之前,先羅列一下通用的命令標記,以下這些命令都可適用的:
名稱說明
-a用于強制重新編譯所有涉及的 Go 語言代碼包(包括 Go 語言標準庫中的代碼包),即使它們已經是最新的了。該標記可以讓我們有機會通過改動底層的代碼包做一些實驗。
-n使命令僅打印其執(zhí)行過程中用到的所有命令,而不去真正執(zhí)行它們。如果不只想查看或者驗證命令的執(zhí)行過程,而不想改變任何東西,使用它正好合適。
-race用于檢測并報告指定 Go 語言程序中存在的數據競爭問題。當用 Go 語言編寫并發(fā)程序的時候,這是很重要的檢測手段之一。
-v用于打印命令執(zhí)行過程中涉及的代碼包。這一定包括我們指定的目標代碼包,并且有時還會包括該代碼包直接或間接依賴的那些代碼包。這會讓你知道哪些代碼包被執(zhí)行過了。
-work用于打印命令執(zhí)行時生成和使用的臨時工作目錄的名字,且命令執(zhí)行完成后不刪除它。這個目錄下的文件可能會對你有用,也可以從側面了解命令的執(zhí)行過程。如果不添加此標記,那么臨時工作目錄會在命令執(zhí)行完畢前刪除。
-x使命令打印其執(zhí)行過程中用到的所有命令,并同時執(zhí)行它們。
1. go run
專門用來運行命令源碼文件的命令,注意,這個命令不是用來運行所有 Go 的源碼文件的!
go run 命令只能接受一個命令源碼文件以及若干個庫源碼文件(必須同屬于 main 包)作為文件參數,且不能接受測試源碼文件。它在執(zhí)行時會檢查源碼文件的類型。如果參數中有多個或者沒有命令源碼文件,那么 go run 命令就只會打印錯誤提示信息并退出,而不會繼續(xù)執(zhí)行。
這個命令具體干了些什么事情呢?來分析分析,我們先重新創(chuàng)建一個新文件:mytest.go,并加入以下代碼:
packagemain
import"fmt"
funcmain(){
? ? fmt.Println("HelloWorld")
? ? fmt.Println("你好,Go!!!")
}
執(zhí)行go run 配合-n:
localhost:hello ruby$ gorun-nmytest.go
?
#
# command-line-arguments
#
?
mkdir-p$WORK/b001/
cat>$WORK/b001/importcfg <<'EOF'# internal
# import config
packagefilefmt=/usr/local/go/pkg/darwin_amd64/fmt.a
packagefileruntime=/usr/local/go/pkg/darwin_amd64/runtime.a
EOF
cd/Users/ruby/go/src/hello
/usr/local/go/pkg/tool/darwin_amd64/compile-o$WORK/b001/_pkg_.a-trimpath$WORK/b001-pmain-complete-buildidieg41NOobNF0eqq3xgnP/ieg41NOobNF0eqq3xgnP-dwarf=false-goversiongo1.12.1-D_/Users/ruby/go/src/hello-importcfg$WORK/b001/importcfg-pack-c=4./mytest.go
/usr/local/go/pkg/tool/darwin_amd64/buildid-w$WORK/b001/_pkg_.a# internal
cat>$WORK/b001/importcfg.link <<'EOF'# internal
...# 此處省略
EOF
mkdir-p$WORK/b001/exe/
cd.
/usr/local/go/pkg/tool/darwin_amd64/link-o$WORK/b001/exe/mytest-importcfg$WORK/b001/importcfg.link-s-w-buildmode=exe-buildid=vpgT856LhbZPXp6WeHib/ieg41NOobNF0eqq3xgnP/ieg41NOobNF0eqq3xgnP/vpgT856LhbZPXp6WeHib-extld=clang$WORK/b001/_pkg_.a
$WORK/b001/exe/mytest
localhost:hello ruby$
?
運行效果圖:

這里可以看到創(chuàng)建了兩個臨時文件夾 b001 和 exe,先執(zhí)行了 compile 命令,然后 link,生成了歸檔文件.a 和 最終可執(zhí)行文件,最終的可執(zhí)行文件放在 exe 文件夾里面。命令的最后一步就是執(zhí)行了可執(zhí)行文件。
總結一下如下圖:

舉個例子,生成的臨時文件可以用go run -work看到,比如當前生成的臨時文件夾是如下的路徑:
localhost:hello ruby$ gorun-workmytest.go
WORK=/var/folders/kt/nlhsnpgn6lgd_q16f8j83sbh0000gn/T/go-build593750496
HelloWorld
你好,Go!!!
localhost:hello ruby$
我們進入:/var/folders/kt/nlhsnpgn6lgd_q16f8j83sbh0000gn/T/go-build593750496目錄,可以看到如下目錄結構:

可以看到,最終go run命令是生成了2個文件,一個是歸檔文件,一個是可執(zhí)行文件。
go run 命令在第二次執(zhí)行的時候,如果發(fā)現導入的代碼包沒有發(fā)生變化,那么 go run 不會再次編譯這個導入的代碼包。直接靜態(tài)鏈接進來。
localhost:hello ruby$ gorun-nmytest.go
mkdir-p$WORK/b001/
cat>$WORK/b001/importcfg.link <<'EOF'# internal
packagefilecommand-line-arguments=/Users/ruby/Library/Caches/go-build/6b/6b9577027c8da20b0ae6da790267f558b3b71eea1feb44039fb933b35eaef6f9-d
packagefilefmt=/usr/local/go/pkg/darwin_amd64/fmt.a
...
EOF
mkdir-p$WORK/b001/exe/
cd.
/usr/local/go/pkg/tool/darwin_amd64/link-o$WORK/b001/exe/mytest-importcfg$WORK/b001/importcfg.link-s-w-buildmode=exe-buildid=goiqf_1cemqljgOYzSRA/ieg41NOobNF0eqq3xgnP/MVbHdxOky1BGK6Aq_4bM/goiqf_1cemqljgOYzSRA-extld=clang /Users/ruby/Library/Caches/go-build/6b/6b9577027c8da20b0ae6da790267f558b3b71eea1feb44039fb933b35eaef6f9-d
$WORK/b001/exe/mytest
localhost:hello ruby$
?
2. go build
go build 命令主要是用于測試編譯。在包的編譯過程中,若有必要,會同時編譯與之相關聯的包。
如果是普通包,當你執(zhí)行go build命令后,不會產生任何文件。
如果是main包,當只執(zhí)行go build命令后,會在當前目錄下生成一個可執(zhí)行文件。如果需要在$GOPATH/bin目錄下生成相應的exe文件,需要執(zhí)行go install 或者使用 go build -o 路徑/可執(zhí)行文件。
如果某個文件夾下有多個文件,而你只想編譯其中某一個文件,可以在 go build 之后加上文件名,例如 go build a.go;go build 命令默認會編譯當前目錄下的所有go文件。
你也可以指定編譯輸出的文件名。比如,我們可以指定go build -o 可執(zhí)行文件名,默認情況是你的package名(非main包),或者是第一個源文件的文件名(main包)。
go build 會忽略目錄下以”_”或者”.”開頭的go文件。
如果你的源代碼針對不同的操作系統需要不同的處理,那么你可以根據不同的操作系統后綴來命名文件。
當代碼包中有且僅有一個命令源碼文件的時候,在文件夾所在目錄中執(zhí)行 go build 命令,會在該目錄下生成一個與目錄同名的可執(zhí)行文件。
// 假設當前文件夾名叫 hello
localhost:hello ruby$ pwd
/Users/ruby/go/src/hello
localhost:hello ruby$ ls
helloworld.go
localhost:hello ruby$ gobuild
localhost:hello ruby$ ls
hello? ? ? helloworld.go
localhost:hello ruby$
于是在當前目錄直接生成了以當前文件夾為名的可執(zhí)行文件( 在 Mac 平臺下是 Unix executable 文件,在 Windows 平臺下是 exe 文件)

但是這種情況下,如果使用 go install 命令,如果 GOPATH 里面只有一個工作區(qū),就會在當前工作區(qū)的 bin 目錄下生成相應的可執(zhí)行文件。如果 GOPATH 下有多個工作區(qū),則是在 GOBIN 下生成對應的可執(zhí)行文件。
localhost:hello ruby$ goinstall
go install hello: open /usr/local/go/bin/hello: permission denied
localhost:hello ruby$

這個問題是因為它需要創(chuàng)建bin目錄,然后把可剛才的可執(zhí)行文件放進去,而目前我們在gopath下還沒有bin目錄,那么就需要先創(chuàng)建這個文件,而普通用戶沒有直接創(chuàng)建文件夾的權限,這個和Go語言的命令是沒有關系的。我們可以加上sodu 來執(zhí)行這個命令,表示使用管理員的身份執(zhí)行,然后輸入密碼,那么就可以創(chuàng)建bin這個文件夾了。
再次執(zhí)行:
localhost:hello ruby$ sudogo install
Password:
localhost:hello ruby$
?
執(zhí)行完 go install 會發(fā)現可執(zhí)行文件不見了!去哪里了呢?其實是被移動到了 bin 目錄下了(如果 GOPATH 下有多個工作區(qū),就會放在GOBIN 目錄下)。
查看目錄:

那 go build 和 go install 究竟干了些什么呢?
先來說說 go build。go build 用于編譯我們指定的源碼文件或代碼包以及它們的依賴包。但是注意如果用來編譯非命令源碼文件,即庫源碼文件,go build 執(zhí)行完是不會產生任何結果的。這種情況下,go build 命令只是檢查庫源碼文件的有效性,只會做檢查性的編譯,而不會輸出任何結果文件。
go build 編譯命令源碼文件,則會在該命令的執(zhí)行目錄中生成一個可執(zhí)行文件,上面的例子也印證了這個過程。
go build 后面不追加目錄路徑的話,它就把當前目錄作為代碼包并進行編譯。go build 命令后面如果跟了代碼包導入路徑作為參數,那么該代碼包及其依賴都會被編譯。
go build 命令究竟做了些什么呢?我們可以執(zhí)行-n這個命令來查看:
localhost:hello ruby$ gobuild-n
?
#
# hello
#
?
mkdir-p$WORK/b001/
cat>$WORK/b001/importcfg <<'EOF'# internal
# import config
packagefilefmt=/usr/local/go/pkg/darwin_amd64/fmt.a
packagefileruntime=/usr/local/go/pkg/darwin_amd64/runtime.a
EOF
cd/Users/ruby/go/src/hello
/usr/local/go/pkg/tool/darwin_amd64/compile-o$WORK/b001/_pkg_.a-trimpath$WORK/b001-pmain-complete-buildidPXDetO1R1NhLFMK5QGUc/PXDetO1R1NhLFMK5QGUc-goversiongo1.12.1-D""-importcfg$WORK/b001/importcfg-pack-c=4./helloworld.go
/usr/local/go/pkg/tool/darwin_amd64/buildid-w$WORK/b001/_pkg_.a# internal
cat>$WORK/b001/importcfg.link <<'EOF'# internal
packagefilehello=$WORK/b001/_pkg_.a
...
EOF
mkdir-p$WORK/b001/exe/
cd.
/usr/local/go/pkg/tool/darwin_amd64/link-o$WORK/b001/exe/a.out-importcfg$WORK/b001/importcfg.link-buildmode=exe-buildid=diTh1q6kcbGRIX3aj3mU/PXDetO1R1NhLFMK5QGUc/PXDetO1R1NhLFMK5QGUc/diTh1q6kcbGRIX3aj3mU-extld=clang$WORK/b001/_pkg_.a
/usr/local/go/pkg/tool/darwin_amd64/buildid-w$WORK/b001/exe/a.out# internal
mv$WORK/b001/exe/a.out hello
localhost:hello ruby$
?
可以看到,執(zhí)行過程和 go run 大體相同,唯一不同的就是在最后一步,go run 是執(zhí)行了可執(zhí)行文件,但是 go build 命令,只是把庫源碼文件編譯了一遍,然后把可執(zhí)行文件移動到了當前目錄的文件夾中。
總結一下如下圖:

3. go install
go install 命令是用來編譯并安裝代碼包或者源碼文件的。
go install 命令在內部實際上分成了兩步操作:第一步是生成結果文件(可執(zhí)行文件或者.a包),第二步會把編譯好的結果移到$GOPATH/pkg或者?$GOPATH/bin。
可執(zhí)行文件: 一般是 go install 帶main函數的go文件產生的,有函數入口,所有可以直接運行。
.a應用包: 一般是 go install 不包含main函數的go文件產生的,沒有函數入口,只能被調用。
go install 用于編譯并安裝指定的代碼包及它們的依賴包。當指定的代碼包的依賴包還沒有被編譯和安裝時,該命令會先去處理依賴包。與 go build 命令一樣,傳給 go install 命令的代碼包參數應該以導入路徑的形式提供。并且,go build 命令的絕大多數標記也都可以用于實際上,go install 命令只比 go build 命令多做了一件事,即:安裝編譯后的結果文件到指定目錄。
安裝代碼包會在當前工作區(qū)的 pkg 的平臺相關目錄下生成歸檔文件(即 .a 文件)。安裝命令源碼文件會在當前工作區(qū)的 bin 目錄(如果 GOPATH 下有多個工作區(qū),就會放在 GOBIN 目錄下)生成可執(zhí)行文件。
同樣,go install 命令如果后面不追加任何參數,它會把當前目錄作為代碼包并安裝。這和 go build 命令是完全一樣的。
go install 命令后面如果跟了代碼包導入路徑作為參數,那么該代碼包及其依賴都會被安裝。
go install 命令后面如果跟了命令源碼文件以及相關庫源碼文件作為參數的話,只有這些文件會被編譯并安裝。
go install 命令究竟做了些什么呢?
localhost:hello ruby$ goinstall-n
?
#
# hello
#
?
mkdir-p$WORK/b001/
cat>$WORK/b001/importcfg <<'EOF'# internal
# import config
packagefilefmt=/usr/local/go/pkg/darwin_amd64/fmt.a
packagefileruntime=/usr/local/go/pkg/darwin_amd64/runtime.a
EOF
cd/Users/ruby/go/src/hello
/usr/local/go/pkg/tool/darwin_amd64/compile-o$WORK/b001/_pkg_.a-trimpath$WORK/b001-pmain-complete-buildidE1CTs4eXkD5M28s_FQXT/E1CTs4eXkD5M28s_FQXT-goversiongo1.12.1-D""-importcfg$WORK/b001/importcfg-pack-c=4./helloworld.go
/usr/local/go/pkg/tool/darwin_amd64/buildid-w$WORK/b001/_pkg_.a# internal
cat>$WORK/b001/importcfg.link <<'EOF'# internal
packagefilehello=$WORK/b001/_pkg_.a
packagefilefmt=/usr/local/go/pkg/darwin_amd64/fmt.a
...
EOF
mkdir-p$WORK/b001/exe/
cd.
/usr/local/go/pkg/tool/darwin_amd64/link-o$WORK/b001/exe/a.out-importcfg$WORK/b001/importcfg.link-buildmode=exe-buildid=FJ6kJTmN9rcWcwLhqfiQ/E1CTs4eXkD5M28s_FQXT/E1CTs4eXkD5M28s_FQXT/FJ6kJTmN9rcWcwLhqfiQ-extld=clang$WORK/b001/_pkg_.a
/usr/local/go/pkg/tool/darwin_amd64/buildid-w$WORK/b001/exe/a.out# internal
mkdir-p/usr/local/go/bin/
mv$WORK/b001/exe/a.out /usr/local/go/bin/hello
localhost:hello ruby$
?
前面幾步依舊和 go run 、go build 完全一致,只是最后一步的差別,go install 會把命令源碼文件安裝到當前工作區(qū)的 bin 目錄(如果 GOPATH 下有多個工作區(qū),就會放在 GOBIN 目錄下)。如果是庫源碼文件,就會被安裝到當前工作區(qū)的 pkg 的平臺相關目錄下。
總結一下如下圖:

在安裝多個庫源碼文件時有可能遇到如下的問題:
localhost:hello ruby$ go install envir.go fpath.go ipath.go pnode.go util.go
go install: no install locationfor.go files listed on command line (GOBIN notset)
而且,在我們?yōu)榄h(huán)境變量 GOBIN 設置了正確的值之后,這個錯誤提示信息仍然會出現。這是因為,只有在安裝命令源碼文件的時候,命令程序才會將環(huán)境變量 GOBIN 的值作為結果文件的存放目錄。而在安裝庫源碼文件時,在命令程序內部的代表結果文件存放目錄路徑的那個變量不會被賦值。最后,命令程序會發(fā)現它依然是個無效的空值。所以,命令程序會同樣返回一個關于“無安裝位置”的錯誤。這就引出一個結論,我們只能使用安裝代碼包的方式來安裝庫源碼文件,而不能在 go install 命令羅列并安裝它們。另外,go install 命令目前無法接受標記-o以自定義結果文件的存放位置。這也從側面說明了 go install 命令不支持針對庫源碼文件的安裝操作。
4. go get
go get 命令用于從遠程代碼倉庫(比如 Github )上下載并安裝代碼包。注意,go get 命令會把當前的代碼包下載到 $GOPATH 中的第一個工作區(qū)的 src 目錄中,并安裝。
使用 go get 下載第三方包的時候,依舊會下載到 $GOPATH 的第一個工作空間,而非 vendor 目錄。當前工作鏈中并沒有真正意義上的包依賴管理,不過好在有不少第三方工具可選。
如果在 go get 下載過程中加入-d 標記,那么下載操作只會執(zhí)行下載動作,而不執(zhí)行安裝動作。比如有些非常特殊的代碼包在安裝過程中需要有特殊的處理,所以我們需要先下載下來,所以就會用到-d 標記。
還有一個很有用的標記是-u標記,加上它可以利用網絡來更新已有的代碼包及其依賴包。如果已經下載過一個代碼包,但是這個代碼包又有更新了,那么這時候可以直接用-u標記來更新本地的對應的代碼包。如果不加這個-u標記,執(zhí)行 go get 一個已有的代碼包,會發(fā)現命令什么都不執(zhí)行。只有加了-u標記,命令會去執(zhí)行 git pull 命令拉取最新的代碼包的最新版本,下載并安裝。
命令 go get 還有一個很值得稱道的功能——智能下載。在使用它檢出或更新代碼包之后,它會尋找與本地已安裝 Go 語言的版本號相對應的標簽(tag)或分支(branch)。比如,本機安裝 Go 語言的版本是1.x,那么 go get 命令會在該代碼包的遠程倉庫中尋找名為 “go1” 的標簽或者分支。如果找到指定的標簽或者分支,則將本地代碼包的版本切換到此標簽或者分支。如果沒有找到指定的標簽或者分支,則將本地代碼包的版本切換到主干的最新版本。
go get 常用的一些標記如下:
標記名稱標記描述
-d讓命令程序只執(zhí)行下載動作,而不執(zhí)行安裝動作。
-f僅在使用-u標記時才有效。該標記會讓命令程序忽略掉對已下載代碼包的導入路徑的檢查。如果下載并安裝的代碼包所屬的項目是你從別人那里 Fork 過來的,那么這樣做就尤為重要了。
-fix讓命令程序在下載代碼包后先執(zhí)行修正動作,而后再進行編譯和安裝。
-insecure允許命令程序使用非安全的 scheme(如 HTTP )去下載指定的代碼包。如果你用的代碼倉庫(如公司內部的 Gitlab )沒有HTTPS 支持,可以添加此標記。請在確定安全的情況下使用它。
-t讓命令程序同時下載并安裝指定的代碼包中的測試源碼文件中依賴的代碼包。
-u讓命令利用網絡來更新已有代碼包及其依賴包。默認情況下,該命令只會從網絡上下載本地不存在的代碼包,而不會更新已有的代碼包。
go get 命令究竟做了些什么呢?我們還是來打印一下每一步的執(zhí)行過程。
localhost:hello ruby$ goget-xgithub.com/go-errors/errors
cd.
gitclone https://github.com/go-errors/errors /Users/ruby/go/src/github.com/go-errors/errors
cd/Users/ruby/go/src/github.com/go-errors/errors
gitsubmodule update--init--recursive
cd/Users/ruby/go/src/github.com/go-errors/errors
gitshow-ref
cd/Users/ruby/go/src/github.com/go-errors/errors
gitsubmodule update--init--recursive
WORK=/var/folders/kt/nlhsnpgn6lgd_q16f8j83sbh0000gn/T/go-build188558329
localhost:hello ruby$
效果圖:

這里可以很明顯的看到,執(zhí)行完 go get 命令以后,會調用 git clone 方法下載源碼,并編譯,最終會把庫源碼文件編譯成歸檔文件安裝到 pkg 對應的相關平臺目錄下。

總結一下如下圖:

5. 其他命令
go clean
go clean 命令是用來移除當前源碼包里面編譯生成的文件,這些文件包括
_obj/ 舊的object目錄,由Makefiles遺留
_test/ 舊的test目錄,由Makefiles遺留
_testmain.go 舊的gotest文件,由Makefiles遺留
test.out 舊的test記錄,由Makefiles遺留
build.out 舊的test記錄,由Makefiles遺留
*.[568ao] object文件,由Makefiles遺留
DIR(.exe) 由 go build 產生
DIR.test(.exe) 由 go test -c 產生
MAINFILE(.exe) 由 go build MAINFILE.go產生
go fmt
go fmt 命令主要是用來幫你格式化所寫好的代碼文件。
比如我們寫了一個格式很糟糕的 test.go 文件,我們只需要使用 fmt go test.go 命令,就可以讓go幫我們格式化我們的代碼文件。但是我們一般很少使用這個命令,因為我們的開發(fā)工具一般都帶有保存時自動格式化功能,這個功能底層其實就是調用了 go fmt 命令而已。
使用go fmt命令,更多時候是用gofmt,而且需要參數-w,否則格式化結果不會寫入文件。gofmt -w src,可以格式化整個項目。
go test
go test 命令,會自動讀取源碼目錄下面名為*_test.go的文件,生成并運行測試用的可執(zhí)行文件。默認的情況下,不需要任何的參數,它會自動把你源碼包下面所有test文件測試完畢,當然你也可以帶上參數,詳情請參考go help testflag
go doc
go doc 命令其實就是一個很強大的文檔工具。
如何查看相應package的文檔呢? 例如builtin包,那么執(zhí)行go doc builtin;如果是http包,那么執(zhí)行go doc net/http;查看某一個包里面的函數,那么執(zhí)行go doc fmt Printf;也可以查看相應的代碼,執(zhí)行go doc -src fmt Printf;
# 查看net/http包
localhost:hello ruby$ godoc net/http
# 查看time包
localhost:hello ruby$ godoc time
# 查看某個包里的指定函數
localhost:hello ruby$ godoc fmt Printf
通過命令在命令行執(zhí)行 go doc -http=:端口號,比如godoc -http=:8080。然后在瀏覽器中打開127.0.0.1:8080,你將會看到一個golang.org的本地copy版本,通過它你可以查詢pkg文檔等其它內容。如果你設置了GOPATH,在pkg分類下,不但會列出標準包的文檔,還會列出你本地GOPATH中所有項目的相關文檔,這對于經常被限制訪問的用戶來說是一個不錯的選擇。
localhost:hello ruby$ godoc-http=:9527
go fix 用來修復以前老版本的代碼到新版本,例如go1之前老版本的代碼轉化到go1
go version 查看go當前的版本
go env 查看當前go的環(huán)境變量
go list 列出當前全部安裝的package