我們學習 Go 語言時,要做的第一件事,都是根據自己電腦的計算架構(比如,是 32 位的計算機還是 64 位的計算機)以及作業系統(比如,是 Windows 還是 Linux),從Go 語言官網下載對應的二進制包,也就是可以拿來即用的安裝包,
隨后,我們會解壓縮安裝包、放置到某個目錄、配置環境變數,并通過在命令列中輸入go version來驗證是否安裝成功,
在這個程序中,我們還需要配置 3 個環境變數,也就是 GOROOT、GOPATH 和 GOBIN,這里我可以簡單介紹一下,
- GOROOT:Go 語言安裝根目錄的路徑,也就是 GO 語言的安裝路徑,
- GOPATH:若干作業區目錄的路徑,是我們自己定義的作業空間,
- GOBIN:GO 程式生成的可執行檔案(executable file)的路徑,
其中,GOPATH 背后的概念是最多的,也是最重要的,那么,今天我們的面試問題是:你知道設定 GOPATH 有什么意義嗎?
典型回答:你可以把 GOPATH 簡單理解成 Go 語言的作業目錄,它的值是一個目錄的路徑,也可以是多個目錄路徑,每個目錄都代表 Go 語言的一個作業區(workspace),
我們需要利于這些作業區,去放置 Go 語言的原始碼檔案(source file),以及安裝(install)后的歸檔檔案(archive file,也就是以“.a”為擴展名的檔案)和可執行檔案(executable file),
事實上,由于 Go 語言專案在其生命周期內的所有操作(編碼、依賴管理、構建、測驗、安裝等)基本上都是圍繞著 GOPATH 和作業區進行的,所以,它的背后至少有 3 個知識點,分別是:
1. Go 語言原始碼的組織方式是怎樣的;
2. 你是否了解原始碼安裝后的結果(只有在安裝后,Go 語言原始碼才能被我們或其他代碼使用);
3. 你是否理解構建和安裝 Go 程式的程序(這在開發程式以及查找程式問題的時候都很有用,否則你很可能會走彎路),
知識擴展
1. Go 語言原始碼的組織方式
與許多編程語言一樣,Go 語言的原始碼也是以代碼包為基本組織單位的,在檔案系統中,這些代碼包其實是與目錄一一對應的,由于目錄可以有子目錄,所以代碼包也可以有子包,
一個代碼包中可以包含任意個以.go 為擴展名的原始碼檔案,這些原始碼檔案都需要被宣告屬于同一個代碼包,
代碼包的名稱一般會與原始碼檔案所在的目錄同名,如果不同名,那么在構建、安裝的程序中會以代碼包名稱為準,
每個代碼包都會有匯入路徑,代碼包的匯入路徑是其他代碼在使用該包中的程式物體時,需要引入的路徑,在實際使用程式物體之前,我們必須先匯入其所在的代碼包,具體的方式就是import該代碼包的匯入路徑,就像這樣:
import "github.com/mailru/easyjson"
在作業區中,一個代碼包的匯入路徑實際上就是從 src 子目錄,到該包的實際存盤位置的相對路徑,
所以說,Go 語言原始碼的組織方式就是以環境變數 GOPATH、作業區、src 目錄和代碼包為主線的,一般情況下,Go 語言的原始碼檔案都需要被存放在環境變數 GOPATH 包含的某個作業區(目錄)中的 src 目錄下的某個代碼包(目錄)中,
2. 了解原始碼安裝后的結果
了解了 Go 語言原始碼的組織方式后,我們很有必要知道 Go 語言原始碼在安裝后會產生怎樣的結果,
原始碼檔案以及安裝后的結果檔案都會放到哪里呢?我們都知道,原始碼檔案通常會被放在某個作業區的 src 子目錄下,
那么在安裝后如果產生了歸檔檔案(以“.a”為擴展名的檔案),就會放進該作業區的 pkg 子目錄;如果產生了可執行檔案,就可能會放進該作業區的 bin 子目錄,
我再講一下歸檔檔案存放的具體位置和規則,
原始碼檔案會以代碼包的形式組織起來,一個代碼包其實就對應一個目錄,安裝某個代碼包而產生的歸檔檔案是與這個代碼包同名的,
放置它的相對目錄就是該代碼包的匯入路徑的直接父級,比如,一個已存在的代碼包的匯入路徑是
github.com/mailru/easyjson
那么執行命令
go install github.com/mailru/easyjson
生成的歸檔檔案的相對目錄就是github.com/mailru,檔案名為easyjson.a,
順便說一下,上面這個代碼包匯入路徑還有另外一層含義,那就是:該代碼包的原始碼檔案存在于 GitHub 網站的 mailru組的代碼倉庫 easyjson中,
再說回來,歸檔檔案的相對目錄與 pkg 目錄之間還有一級目錄,叫做平臺相關目錄,平臺相關目錄的名稱是由 build(也稱“構建”)的目標作業系統、下劃線和目標計算架構的代號組成的,
比如,構建某個代碼包時的目標作業系統是 Linux,目標計算架構是 64 位的,那么對應的平臺相關目錄就是 linux_amd64,
因此,上述代碼包的歸檔檔案就會被放置在當前作業區的子目錄pkg/windows_amd64/github.com/mailru中,

總之,你需要記住的是,某個作業區的 src 子目錄下的原始碼檔案在安裝后一般會被放置到當前作業區的 pkg 子目錄下對應的目錄中,或者被直接放置到該作業區的 bin 子目錄中,
3. 理解構建和安裝 Go 程式的程序
我們再來說說構建和安裝 Go 程式的程序都是怎樣的,以及它們的異同點
構建使用命令go build,安裝使用命令go install,構建和安裝代碼包的時候都會執行編譯、打包等操作,并且,這些操作生成的任何檔案都會先被保存到某個臨時的目錄中,
如果構建的是庫原始碼檔案,那么操作后產生的結果檔案只會存在于臨時目錄中,這里的構建的主要意義在于檢查和驗證,
如果構建的是命令原始碼檔案,那么操作的結果檔案會被搬運到原始碼檔案所在的目錄中,
安裝操作會先執行構建,然后還會進行鏈接操作,并且把結果檔案搬運到指定目錄,
進一步說,如果安裝的是庫原始碼檔案,那么結果檔案會被搬運到它所在作業區的 pkg 目錄下的某個子目錄中,
如果安裝的是命令原始碼檔案,那么結果檔案會被搬運到它所在作業區的 bin 目錄中,或者環境變數GOBIN指向的目錄中,
這里你需要記住的是,構建和安裝的不同之處,以及執行相應命令后得到的結果檔案都會出現在哪里,
總結
作業區和 GOPATH 的概念和含義是每個 Go 工程師都需要了解的,雖然它們都比較簡單,但是說它們是 Go 程式開發的核心知識并不為過,
然而,我在招聘面試的程序中仍然發現有人忽略掉了它們,Go 語言提供的很多工具都是在 GOPATH 和作業區的基礎上運行的,比如上面提到的go build、go install和go get,這三個命令也是我們最常用到的,
思考題
- Go 語言在多個作業區中查找依賴包的時候是以怎樣的順序進行的?
- 如果在多個作業區中都存在匯入路徑相同的代碼包會產生沖突嗎?
這兩個問題之間其實是有一些關聯的,答案并不復雜,你做幾個試驗幾乎就可以找到它了,你也可以看一下 Go 語言標準庫中go build包及其子包的原始碼,那里面的寶藏也很多,可以助你深刻理解 Go 程式的構建程序,
補充
go build 命令一些可選項的用途和用法
在運行go build命令的時候,默認不會編譯目標代碼包所依賴的那些代碼包,當然,如果被依賴的代碼包的歸檔檔案不存在,或者原始碼檔案有了變化,那它還是會被編譯,
如果要強制編譯它們,可以在執行命令的時候加入標記-a,此時,不但目標代碼包總是會被編譯,它依賴的代碼包也總會被編譯,即使依賴的是標準庫中的代碼包也是如此,
另外,如果不但要編譯依賴的代碼包,還要安裝它們的歸檔檔案,那么可以加入標記-i,
那么我們怎么確定哪些代碼包被編譯了呢?有兩種方法,
- 運行go build命令時加入標記-x,這樣可以看到go build命令具體都執行了哪些操作,另外也可以加入標記-n,這樣可以只查看具體操作而不執行它們,
- 運行go build命令時加入標記-v,這樣可以看到go build命令編譯的代碼包的名稱,它在與-a標記搭配使用時很有用,
下面再說一說與 Go 原始碼的安裝聯系很緊密的一個命令:go get,
命令go get會自動從一些主流公用代碼倉庫(比如 GitHub)下載目標代碼包,并把它們安裝到環境變數GOPATH包含的第 1 作業區的相應目錄中,如果存在環境變數GOBIN,那么僅包含命令原始碼檔案的代碼包會被安裝到GOBIN指向的那個目錄,
最常用的幾個標記有下面幾種,
- -u:下載并安裝代碼包,不論作業區中是否已存在它們,
- -d:只下載代碼包,不安裝代碼包,
- -fix:在下載代碼包后先運行一個用于根據當前 Go 語言版本修正代碼的工具,然后再安裝代碼包,
- -t:同時下載測驗所需的代碼包,
- -insecure:允許通過非安全的網路協議下載和安裝代碼包,HTTP 就是這樣的協議,
Go 語言官方提供的go get命令是比較基礎的,其中并沒有提供依賴管理的功能,目前 GitHub 上有很多提供這類功能的第三方工具,比如glide、gb以及官方出品的dep、vgo等等,它們在內部大都會直接使用go get,
附基礎知識圖譜

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/251942.html
標籤:Go
