Go 語言中 GoPath 模式與 GoModules 模式介紹


GoPath 模式

當你在電腦上安裝好 Go 后,在終端執行 go env 命令,在輸出的內容中,你會發現一個 GOPATH 的環境變量,它的值是一個目錄路徑。

從 Go 1.8 版本開始,安裝 Go 開發包時會默認為 GOPATH 變量設置一個目錄路徑,它表示的是 Go 語言的工作目錄,這個目錄下會有三個子目錄,它們分別是:

  • bin:存放編譯后生成的二進制可執行文件

  • pkg:存放編譯后生成的 .a文件

  • src:存放項目的源代碼,有自己寫的代碼,還有通過 go get命令下載的包

注意當你第一次安裝 Go 時,你的電腦上不一定存在 GOPATH 目錄,你需要自己創建 GOPATH 的目錄。

而所謂的『GoPath開發模式』就是指將項目文件和下載的包放到 $GOPATH/src目錄下進行管理的方式。

GoPath 模式的弊端

在 Go 1.11版本之前,開發者是必須要配置 這個GOPATH環境變量的,這種代碼代碼管理模式存在比較嚴重的問題就是沒有版本控制。

因為多個項目都會放在src目錄下,而每個項目依賴的一些第三方包也是下載在src目錄下的,當升級某個依賴包時那就是全局升級了,引用這個依賴包的項目都跟着升級包版本了,這樣是一件很危險的事,你不知道升級的包在另外一個項目中是否能正常運行的。而且當多人協同開發時,你不知道別人下載的包是不是你所用的那個版本,容易出錯且不好排查原因。

vendor 方案

其實針對 GOPATH 這種方式的弊端,官方也給出了解決方案,就是引入 vendor。解決的思路就是,在每個項目下都創建一個 vendor 目錄,每個項目所需的依賴都只會下載到自己vendor目錄下,項目之間的依賴包就互不影響了。在使用包時,會先從當前項目下的 vendor 目錄查找,然后依次向上級目錄查找。這種方式依舊是 GOPATH 模式下的,它解決了不同項目不能使用不同版本庫的問題,但是也並不完美。如果多個項目使用的第三方庫版本是一樣的,那么就會造成相同的庫存在多個目錄下,占用空間而且沒辦法集中管理,再一個就是當你要分享自己的項目時,除了源碼,還要上傳所有依賴的包,才能保證別人使用時不會因為版本問題報錯。

官方已經不推薦 GOPATH 的開發模式了,新版本中推薦使用 GoModules 模式,一起來看看。

GoModules 模式

GoModules 模式是 Go 語言 1.11 版本正式推出的,在 1.14 版本時,官方就發話 GoModules 的模擬已經成熟,可以用於生產環境了。所以新學習者們,可以直接用上這種模式了!

使用 GoModules 模式主要依賴於官方發布了自己的包管理工具,即 mod,如果做過前端的話,那你一定熟悉 npm,mod 就是類似於 npm 的工具。當你要使用 GoModules 模式時,你需要主動開啟它,在終端輸入命令 go env 時,你會發現一個 GO111MODULE 變量:

它就是開關,默認是 “auto” 模式,它所有可以設置的值有:

  1. auto: 自動模式,當項目下存在 go.mod 文件時,就啟用 GoModules 模式;
  2. on: 開啟模塊支持,編譯時會忽略 GOPATH 和 vendor 文件夾,只根據 go.mod下載依賴;
  3. off: 關閉模塊支持,使用 GOPATH 模式。

所以當你要使用 GoModules 模式時,你需要執行開啟命令:

go env -w GO111MODULE=on

注意,如果上面這個命令執行后提示無權限修改系統環境變量時,你也可以在通過 vim ~/.bash_profile 的方式,在其中添加 export GO111MODULE=on 的方式修改,別忘了添加后要執行 source ~/.bash_profile。如果你電腦上終端用的是zsh,你還需要在 ~/.zshrc 文件中添加 source ~/.bash_profile這一行。

然后 go env 查看一下是否開啟成功:

當你開啟 GoModules 模式時,你就無需將你的 go 項目放到 $GOPATH/src 目錄下了,其實在新版 Go 的默認情況下,你就可以把項目隨意放置了。接下來就看下怎么用 mod。

使用 go mod 初始化項目

go mod 的命令主要有:

go mod download    // 下載依賴的module到本地cache(默認為$GOPATH/pkg/mod目錄)
go mod edit        // 編輯go.mod文件
go mod graph       // 打印模塊依賴圖
go mod init        // 初始化當前文件夾, 創建go.mod文件
go mod tidy        // 增加缺少的module,刪除無用的module
go mod vendor      // 將依賴復制到vendor下
go mod verify      // 校驗依賴
go mod why         // 解釋為什么需要依賴

我們主要使用 go mod init 來初始化項目,比如我們新建了一個項目目錄 go-demo,那么就需要執行以下命令:

// 需要進入到項目里面
cd go-demo
// 執行 init,init 后面的是自定義的當前項目的包名
go mod init goDemo

此時項目下就會多出一個 go.mod 文件,它的內容如下:

module goDemo  // 定義的包名

go 1.16  // 當前使用的 go 版本

下載第三方包

我們嘗試下載一個第三方包,使用 go get 命令:

go get github.com/jinzhu/now

注意:如果你下載錯誤或者緩慢,可能是因為沒有設置 GOPROXY 代理,可以參考我的這篇記錄:傳送門

下載完成后,就會發現項目下多出一個 go.sum 文件,它的作用相當於鎖定了當前項⽬依賴的所有模塊版本,保證今后項目依賴的版本不會被篡改,更多的介紹可以自行搜索相關文檔,一般我們不用管這個。

再看看 go.mod 文件中,多了一行 require github.com/jinzhu/now v1.1.2 // indirect ,這表示當前項目引入了這個包,其中注釋 // indirect 表示的是間接的依賴,你可以理解為直接依賴的是 jiinzhu,間接依賴的是 now

這里通過 go get 下載的包儲是存在 $GOPATH/pkg/mod 目錄下,同時會根據引入的路徑來保存,比如上面下載的這個包,它的存放位置就是 $GOPATH/pkg/mod/github.com/jinzhu。注意 GOPATH 模式下,下載的包是存在 $GOPATH/src 目錄下的。

下載指定版本的第三方包

在GoModules 模式下,你也可以下載指定版本的包,比如 go get github.com/jinzhu/now@v1.1.0,此時在 $GOPATH 的包目錄下就存在兩個版本的包文件:

因為允許多版本包的存在,所以就不會出現只能用一個版本包的尷尬境地,也不用怕一個項目升級包版本而影響到另外一個項目。

無論你是升級版本還是降級版本,你都可以很方便地替換項目中引入的包版本,使用 go mod edit -replace

cd go-demo

go mod edit -replace=now@v1.1.2=now@v1.1.0 // 表示當引入 v.1.1.2 時其實找到的是 v.1.1.0

此時 go.mod 文件變成這樣:

module goDemo

go 1.16

require github.com/jinzhu/now v1.1.2 // indirect

replace now v1.1.2 => now v1.1.0 // replace 生效

結尾

關於 Go 語言開發的這兩種模式,就介紹到這里了,更多細節要在實際開發中慢慢掌握,后續我可能會補充這部分內容,只是作為初學者,我覺得了解到這里就夠了。

兩種模式的簡單總結:

  • GOPATH 模式:項目文件夾和包文件都需要都放在 $GOPATH/src 目錄下,不方便控制依賴包版本,一次包升級,所有依賴的項目都升級;
  • GoModules 模式:項目可以放在任意位置,新版本的 go 默認就可以把項目放在任意位置,通過 go mod 來管理依賴包,允許多個包版本存在,每個項目都維護自己的一份包版本,互不影響。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM