Go語言之項目的包結構詳解
src
bin
pkg
對於bin和pkg兩個目錄,主要影響go install/get命令,它們會將編譯結果安裝到這兩個目錄下,以實現增量編譯。
環境變量用於實現GOPATH只是工具鏈和標準庫的存放位置。
在使用Git等版本控制工具的時候,建議忽略pkg和bin目錄。直接在src目錄或者直接在子包目錄下創建倉庫。
導入包:必須用import命令,參數是工作空間以src為起始的絕對路徑。
除了使用默認的包名以外還可以使用別名機制來實現避免同名沖突問題。
import導入的是路徑而不是包名,import的導入方式:
1.import "github.com/test/tester" 默認的方式導入
2.import X "github.com/test/tester" 別名方式導入
3.import . "github.com/test/tester" 簡單方式導入(不建議使用,因為有可能會造成命名沖突)
4.import _ "github.com/test/tester" 初始化的方式導入
簡便方式常用於代碼測試中。未使用的包導入後會報錯,可以使用初始化方式進行忽略。
部分工具支持相對路徑。
自定義路徑:在Web服務器上對應路徑名稱使用go-import跳轉信息即可。
組織結構:
包名通常使用單數形式,源碼文件必須必使用UTF-8格式,否則會導致編譯出錯。使用go list命令可以列出包路徑。
main包:可執行的入口(入口函數:main.main)
all包:標準庫以及GOPATH中找到的所有包
std/cmd包:標準庫以及工具鏈
documentation庫:存儲文檔信息,無法導入(和目錄名無關)
權限:所有成員在包內都能訪問,無論是否在同一的源碼內,但是只有名稱首字母大寫才會在包外可視。
初始化:
包內每個源碼文件可以定義一個或者是多個初始化函數,但是編譯器不保證執行次序。
實際上,所有這些初始化函數(包括標準庫和導入的第三方包)都是由編譯器自動生成的一個包裝函數進行調用,因此可保證在單一線程上執行,且僅僅執行一次。執行次序和依賴關系、文件名以及定義次序有關。
初始化函數之間不應有邏輯關聯,最好僅僅處理當前文件的初始化操作。編譯器首先確保完成所有全局變量初始化,然後才開始執行初始化函數。如果在初始化函數中引用了全局變量,那麽這個變量最好是在定義的是時候直接賦值。
因為無法保證執行的次序搜一遍任何初始化函數中的賦值都有可能延遲無效。
在進行代碼重構的時候,我們會將代碼陸續的分離出來,以獨立包的形式進行維護,此時,基於首字母大小寫的訪問權限控制是過於粗略的,因為我們希望這些包導出成員僅僅在特定範圍內訪問,而不是向所有用戶公開的。
所保存在internal目錄下面的包(包括自身)僅僅能被父目錄下面的包(含所有層次的子目錄)訪問。
依賴管理:引入vendor的機制,專門存放第三方包,實現將源碼包和依賴完整打包分發。如果說internal針對內部,那麽vendor針對的是外部。vendor比標準庫的優先級要高。
從源文件所在目錄開始,逐級向上構造vendor全路徑,直到發現路徑匹配為止。匹配失敗,則依舊搜索GOPATH。要使用vendor機制,必須開啟"GO15VENDOREXPERIMENT=1"的環境變量,Go1.6中默認是開啟的,並且必須設置Go的工作空間。
使用go get下載第三方包時,依舊使用GOPATH第一個工作空間,而不是vendor目錄,當前工具鏈中並沒有真正意義上的包依賴管理,好在有第三方工具的實現。
Go語言之項目的包結構詳解