1. Workspace
-
工作空間主要由 src、bin、pkg 三個目錄組成。通常需要將空間路徑新增到 GOPATH 環境變數列表中,一遍相關工具能正常工作
-
在工作空間裡,包括子包在內的所有原始碼檔案都儲存在 src 目錄下。至於bin、pkg兩個目錄,其主要影響 go install/get 命令,它們會將編譯結果 (可執行檔案或靜態庫)安裝到這兩個目錄下,以實現增量編譯
環境變數
-
編譯器等相關工具按 GOPATH 設定的路徑搜尋目標。也就是說在匯入目標庫時,排在列表前面的路徑比當前工作空間優先順序更高
-
另外,go get 預設將下載的第三方包儲存到列表中第一個工作空間內
-
-
環境變數 GOROOT 用於指示工具鏈和標準庫的存放位置。在生成工具鏈時,相關路徑就已經嵌入到可執行檔案內,故無須格外設定,但如果出現類似下面這樣的錯誤提示,請檢查路徑是否一致
-
-
除透過設定 GOROOT 環境變數覆蓋內部路徑外,還可以移動目錄 (改名、符號連線等),或重新編譯工具鏈來解決
-
至於 GOBIN ,則是強制代替工作空間的 bin 目錄,作為 go install 目標儲存路徑,這可避免將所有工作空間的 bin 路徑 新增到 PATH 環境變數中
-
在使用 Git 等版本控制工具時,建議忽略 pkg、bin 目錄。直接在 src, 或具體的子包下建立程式碼倉庫 (repository)
2. 匯入包
-
使用標準庫或第三方包前,需使用 import 匯入,引數是工作空間中以 src 為七十的絕對路徑。編譯器從標準庫開始搜尋,然後依次搜尋 GOPATH 列表中的各個工作空間
-
除了使用預設包名外還可以使用別名,以解決同名衝突問題
Attention;
-
import 匯入引數是路徑,而非包名,儘管習慣將包和目錄名保持一致,但這不是強制規定,在程式碼中引用包成員時,使用包名而非目錄名
-
有四種匯入方式
-
預設方式
-
別名方式
-
簡便方式 (常用於單元測試程式碼中,不推薦在正式專案於程式碼中使用。)
-
初始化方式 (無法引用,僅用來初始化目標包,讓目標包的初始化函式得以執行)
不能直接或者間接匯入自己,不支援任何形式的迴圈匯入
-
-
未使用的匯入(不包含初始化方式)會被編譯器視為錯誤
相對路徑
-
除了工作空間和絕對路徑外,部分工具還支援相對路徑。可在非工作空間目錄下,直接執行,編譯一些測試程式碼
-
相對路徑是指:當前目錄,或以“ ./ ” 和 “ ../ ” 開頭的路徑
-
不管是否在 test 目錄下,只要命令列路徑正確,就可以用go build/run/test 進行編譯,執行或測試。但因缺少工作空間相關目錄,go install 會無法工作
-
在設定了 GOPATH 的工作空間中,相對路徑會導致編譯失敗
-
go run 不受此影響,可正常執行
自定義路徑
-
即便將程式碼託管在 GitHub ,但我們依然希望使用自有域名定義下載和匯入路徑。方法很簡單,在 Web 伺服器對應路徑返回中包含 “ go-import ” 跳轉資訊即可
-
使用唯一的匯入路徑,方便日後遷移儲存端,但此方法對 vendor 機制無效
-
3. 組織結構
-
包由一個或多個儲存在同一目錄下(不含子目錄)的原始碼檔案組成。包的用途類似名字空間(namespace),是成員作用域和訪問許可權的邊界
-
包名和目錄名並無關係,不要求保持一致
-
包名常用單數形式
-
原始碼檔案必須使用 UTF-8 格式,否則會導致編譯出錯
-
同一目錄下所有原始碼檔案必須使用相同包名稱,因匯入是使用絕對路徑,所以在搜尋路徑下,包必須有唯一路徑,但無須是唯一名字
有幾個被保留、有特殊含義的包名稱;
-
main:可執行入口(入口函式 mian.mian)
-
all:標準庫以及 GOPATH 中能找到的所有包
-
std,cmd:標準庫及工具鏈
-
documentation:儲存文件資訊,無法匯入(和目錄名無關)
(相關工具忽略以” . “ 或 ” _ “ 開頭的目錄或檔案,但是又允許匯入儲存在這些目錄中的包! )
許可權
-
所有成員在包內均可訪問,無論是否在同一原始碼檔案中。但只有名稱首字母大寫的為可匯出成員,在包外可視 (該規則適用於全域性變數、全域性常量、型別、結構欄位、函式、方法等)
-
可透過指標轉換等方式繞開該限制
初始化
-
包內每個原始碼檔案都可定義一到多個初始化函式,但編譯器不保證執行次序。
-
實際上,所有這些初始化函式(包括標準庫和匯入的第三方包)都由編譯器自動生成的一個包裝函式進行呼叫,因此可保證在單一執行緒上執行,且只執行一次
-
編譯器首先確保完成所有全域性變數初始化,然後才開始執行初始化函式,知道這些全部結束後,執行時才正式進入 main.main 入口函式
-
可以在初始化函式中建立 goroutine,或等到它執行結束
-
如果在多個初始化函式中引用全域性變數,那麼最好在變數定義出直接賦值,因無法保證執行次序,所以任何初始化函式中的賦值都有可能“ 延遲無效 ”
延遲包
-
在進行程式碼重構時,我們會將一些內部模組陸續分離出來,以獨立包形式維護。此時,基於首字母大小寫的訪問許可權控制就顯得過於粗獷。因為我們希望這些包匯出成員僅在特定範圍內訪問,而不是向所有使用者公開
-
內部包機制相當於增加了新的訪問許可權控制:所有儲存在 internal 目錄下的包 ( 包括自身 )僅能被其父目錄下的包 ( 含所有層次的子目錄 )訪問
-
匯入內部包必須使用完整路徑
-
4. 依賴管理
-
如何管理和儲存第三方包,一致存在爭議。將專案所有的第三方依賴都放到一個獨立工作空間中,可能會導致版本衝突。放到專案工作空間,又會把工作目錄搞的面目全非。為此,引入了名為 vendor 的機制,專門存放第三方包,實現將原始碼和依賴完整打包分發
-
如果說 internal 針對內部,那麼 vender 就是 針對外部 (external)
-
匯入 vendor 中的第三方包,引數是以 vendor/ 為起點的絕對路徑。這就避免了 vendor 目錄位置帶來的麻煩,讓匯入無論使用 vender,還是 GOPATH 都能保持一致
ATTENTION
-
vendor 比標準庫優先順序更高
question:當多個 vendor 目錄巢狀時,如何正確查詢目標 ?要知道引入的第三方包也可能存在有自己的 vendor 依賴目錄
answer:從當前原始檔所在目錄開始,逐級向上構造 vendor 全路徑,知道發現路徑匹配的目標為止。匹配失敗,則依舊搜尋 GOPATH
-
要使用 vendor機制,須開啟 ” GO15VENDOREXPERIMENT=1 “ 環境變數開關 ( GO 1.6 以上預設開啟 )且必須是設定了 GOPATH 的工作空間
使用 go get 下載第三方包時,依舊使用 GOPATH 第一個工作空間,而非 vendor 目錄。當前工具鏈中並沒有真正意義上的包管理依賴,好在有不少的第三方工具可以選擇