由淺入深:一個簡單的例子,讓你吃透Go語言自定義的包管理
- 2020 年 4 月 8 日
- 筆記
前言
首先使用hello world,演示Go的包是如何導入的。
package main import "fmt"func main() { fmt.Println("Hello, world")}其中 「fmt」 就是就是Go內置的一個包,包含與格式化和輸出到螢幕相關的各種功能。
包的好處
使用這種方式導入包,有以下3個好處:
- 降低函數方法重名的可能,讓函數保持簡短和簡潔。
- 有效地組織程式碼,很方便導向到標的。
- 只需重新編譯小的程式塊,從而加快編譯速度。例如包fmt,我們不必在每次更改程式時都重新編譯它。
程式碼演示
對於包,僅在單獨程式內的上下文中才有意義,下面做一個示例。本文下述指令,均在windows平台下。
1 - 創建目錄
md go_mod_demo
2 - 進入目錄,並創建包名
go mod init demo.com/pkg/v1
執行後輸出如下
go: creating new go.mod: module demo.com/pkg/v1
這時,目錄下會多出一個 go.mod 文件,內容如下:
module demo.com/pkg/v1 go 1.13
僅設置了包名,和go版本號。
3 - 創建一個包
首先,新建目錄
md math
在該目錄下新建文件 math.go ,程式碼如下
package math func Average(nums []float64) float64 { total := float64(0) for _, x := range nums { total += x } return total / float64(len(nums))}聲明了表明為 math,並聲明了一個求64位浮點數數組的平均值的函數。
4 - 安裝math包
創建完之後,需要安裝這個包,提供外部調用。使用以下指令
go install
5 - 創建主程式文件 main.go 並使用 math 包內函數
程式碼如下:
package main import ( "fmt" "demo.com/pkg/v1/math")func main() { nums := []float64{4.62, 90.31, 18.4, 70, 498} avg := math.Average(nums) fmt.Println(avg)}可以看到,我們導入包的名字為 「demo.com/pkg/v1/math」 ,注意math是路徑名,而非包名。
6 - 檢查依賴關係並編譯
go mod verify go build -o pkg.exe
編譯完成後生成二進位文件 pkg.exe。執行該文件輸出內容如下:
136.26600000000002
7 - 目錄樹
以上步驟我們就完成了這個小的示例,下圖是所有文件的目錄樹。

深入了解編譯過程
對於上述的編譯過程,深入了解有助於我們理解go在包管理和連接上的運用次序。在編譯階段使用以下指令
go build -x -o pkg.exe
會列印出所有編譯設計的步驟。我們逐一分析一下。
WORK=C:UsersADMINI~1AppDataLocalTempgo-build011247454 mkdir -p $WORKb001
進入系統臨時目錄,並創建新的目錄用於操作。
cat >$WORKb001importcfg.link << 'EOF' # internal packagefile demo.com/pkg/v1=C:UsersAdministratorAppDataLocalgo-build7d7dfb70c94793423aa270 96ae5d468f117ab2bdfd36637f56a335e015c7f422f2-d packagefile demo.com/pkg/v1/math=C:UsersAdministratorAppDataLocalgo-build9a9a761d7803a2508 d3bb14baf93c9bb63d690a2d2b96dcee9e2798266bf1a8c27-d packagefile fmt=c:gopkgwindows_amd64fmt.a ……(此處省去若干行) packagefile internal/race=c:gopkgwindows_amd64internalrace.a packagefile internal/syscall/windows/sysdll=c:gopkgwindows_amd64internalsyscallwindowssysd ll.a packagefile internal/syscall/windows/registry=c:gopkgwindows_amd64internalsyscallwindowsre gistry.a EOF
這一步創建臨時連接文件 importcfg.link,並寫入內容。使用了為數較多的編譯後文件。
mkdir -p $WORKb001exe cd . "c:\go\pkg\tool\windows_amd64\link.exe" -o "C:\Users\ADMINI~1\AppData\Local\Temp\go-build011247454\b001\exe\a.out.exe" -importcfg "C:\Users\ADMINI~1\AppData\Local\Temp\go-bui ld011247454\b001\importcfg.link" -buildmode=exe -buildid=DI8V_Sm875LZ1CJe7Zp_/CjatiizQFDsD0wV9omHU/TXwkAnBjuzYJjfIEu300/DI8V_Sm875LZ1CJe7Zp_ -extld=gcc "C:\Users\Administrator\AppData\Local\go-build\7d\7dfb70c94793423aa27096ae5d468f117ab2bdfd36637f56a335e015c7f422f2-d" "c:\go\pkg\tool\windows_amd64\buildid.exe" -w "C:\Users\ADMINI~1\AppData\Local\Temp\go-build011247454\b001\exe\a.out.exe" # internal
這一步創建新目錄exe,並在該目錄下調用 link.exe 文件,使用上一步生成的 importcfg.link 內容。
之後調用 buildid.exe 文件編譯生成目標二進位文件 a.out.exe。
cp $WORKb001exea.out.exe pkg.exe rm -r $WORKb001
這一步將生成的二進位文件重命名拷貝到目標目錄,並清空編譯臨時目錄。
結語
本文通過一個簡單的程式碼示例,逐步編寫程式碼,並將程式碼編譯為二進位文件,涉及到了go在包管理和編譯過程中的方方面面。
「不積跬步無以至千里」,大的項目構建,結構複雜,功能繁多,更需要清楚go在包管理中的原理,可以避免走彎路。
Happy coding :-)

