關于go mod的on,off,auto下引入外部包讀取順序的探索

1.前言

網上的文章魚龍混雜,且都只是給結論,你根本不知道誰說的是對的,誰是錯的,為了得到可信的結論,于是有了這篇文章,所謂——實踐出真知。

2.實驗過程

前期準備

  • 在GOPAHT外部建立目錄 my-app:
    midir my-app

  • 進入my-app,編寫程序, vim main.go:

package main

import "github.com/astaxie/beego"

func main() {
    beego.Run()
}

1. GO111MODULE="on":

1.1 不在$GOPATH/src目錄下

  • 開啟GO MOD:
go env -w GO111MODULE="on"

  • 生成go.mod :
go mod init my-app
image.png
  • 執行 go mod tidy,自動下載包到$GOPATH/pkg/mod:

    image.png

  • vim $GOPATH/pkg/mod/github.com/astaxie/beego@v1.12.3/beego.go
    增加一行 (58行) :

fmt.Println("mod")

當然記得要引入包:import "fmt"

image.png

  • 執行 go run main.go

    image.png

    可以證明確實讀取了 $GOPATH/pkg/mod的beego。

  • 生成 vendor,執行 go mod vendor

  • my-app下執行 vim vendor/github.com/astaxie/beego/beego.go
    還是增加一行 (58行) :

fmt.Println("vendor")

如圖所示:


image.png
  • 執行 go run main.go
    image.png

    可以看到此時優先讀取了 vendor里面的外部包

1.2 在$GOPATH/src目錄下

  • 復制my-app的目錄到$GOPATH/src目錄下
  • 執行go run main.go
    image.png

    可以看到優先讀取的還是vendor
  • 執行 rm -rf vendor
  • 再次 執行go run main.go
    image.png

    依然讀的是mod的。

2. GO111MODULE="off"

先執行命令:

go env -w GO111MODULE="off"

此時我的配置如下:


image.png

2.1 GO111MODULE="off"且項目不在 $GOPATH/src下

  • 還是之前在GOPATH/src外的my-app目錄,復制vendor里面的目錄到GOPATH/src下面:

    image.png

  • 執行vim $GOPATH/src/github.com/astaxie/beego/beego.go
    還是之前的位置,改為

fmt.Println("src")
image.png
  • 執行 go run main.go
    image.png

    直接讀取的是 $GOPATH/src下面的包。

2.2 GO111MODULE="off"且項目在 $GOPATH/src下

  • 還是之前在GOPATH/src外的my-app目錄,整個目錄復制到GOPATH/src;
  • 在 $GOPATH/src/my-app 執行 go run main.go
    image.png

    發現竟然讀的是vendor的。
  • 執行:mv vendor vendor_bak 即去除vendor的影響,再執行 go run main.go
    image.png

    這回讀取的就是src的了。

3. GO111MODULE="auto"

執行:

 go env -w GO111MODULE="auto"

修改后環境變量如下:


image.png

3.1 沒有go.mod 且項目在$GOPATH/src下

注意:記得要在:GOPATH/src,GOPATH/pkg/mod, vendor里面的beego包加入了之前的調試語句:

fmt.Println("src")
fmt.Println("mod")
fmt.Println("vendor")
  • 目錄文件如下:


    image.png
  • 執行 go run main.go
    居然報錯了:

    image.png

  • 看看$GOPATH/src是否有包, ls /mnt/d/GoProjects/src/github.com/astaxie/beego

    image.png

    包是有的。

  • 執行一下:go get -v github.com/astaxie/beego

    image.png

  • 再運行:go run main.go,發現可以了:

    image.png

  • 猜想走的是$GOPATH/pkg/mod里面的包,改了一下, vim /mnt/d/GoProjects/pkg/mod/github.com/astaxie/beego@v1.12.3/beego.go:

    image.png

  • 再運行:go run main.go,證實了:

    image.png

  • 開啟vendor,目錄結構如下:


    image.png

    image.png
  • 運行:go run main.go

    image.png

還是走mod。

查閱資料發現,只要main.go依賴的包用了go.mod,則默認會啟用GOMODULE來下載依賴。

3.2 沒有go.mod 且項目不在$GOPATH/src下

按3.1的流程跑了一遍,測試結果同上。

  • 目錄結構:


    image.png
  • 運行:go run main.go
    image.png

    走的是mod
  • 開啟vendor,目錄結構:


    image.png
  • 運行:go run main.go
    image.png

    還是走的是mod。

意味著,GO111MODULE="auto" 的情況下,只要依賴包包含了go.mod,那么無論有沒有vendor,無論在不在$GOPATH/src下,都會開啟mod,并走mod的外部引入包。

3.3 有go.mod 且項目不在$GOPATH/src下

  • 目錄結構:


    image.png
  • 運行:go run main.go

    image.png

    即有vendor情況下走的是vendor

  • 我們執行以下命令mv vendor vendor_bak去除vendor影響,目錄結構:

    image.png

  • 運行:go run main.go

    image.png

走的是mod。

3.4 有go.mod 且項目在$GOPATH/src下

  • 目錄結構:


    image.png
  • 運行:go run main.go

    image.png

    即有vendor是直接走vendor

  • 我們執行以下命令mv vendor vendor_bak去除vendor影響,目錄結構:

    image.png

  • 運行:go run main.go

    image.png

    走的是mod。

3.結論

1.GO111MODULE="on"

1.1 GO111MODULE="on" 且項目不在 $GOPATH/src下

  • 當vendor目錄存在,優先讀取vendor的外部包
  • 當vendor目錄不存在,讀取$GOPATH/pkg/mod下的外部包

1.2 GO111MODULE="on" 且項目在 $GOPATH/src下

跟上面情況(GO111MODULE="on" 且項目不在 $GOPATH/src下)一致。

2. GO111MODULE="off"

2.1.GO111MODULE="off" 且項目不在 $GOPATH/src下

  • 無論有沒有vendor,直接讀取$GOPATH/src里面的外部引入包,即不會讀取vendor里面的包

2.2.GO111MODULE="off" 且項目在 $GOPATH/src下

  • 有vendor則讀取vendor的外部引入包
  • 沒有vendor則讀取$GOPATH/src里面的外部引入包

3.GO111MODULE="auto"

3.1 沒有go.mod 且項目不在$GOPATH/src下

  • 沒有vendor,且依賴的包里面有go.mod,直接走$GOPATH/pkg/mod
  • 沒有vendor,且依賴的包里面都沒有go.mod,直接走$GOPATH/src (待驗證)
  • 有vendor,也沒有用,只要依賴的包里面有go.mod,還是走$GOPATH/pkg/mod
  • 有vendor,且依賴的包里面都沒有go.mod,走$GOPATH/src (待驗證)

3.2 沒有go.mod 且項目在$GOPATH/src下

  • 沒有vendor,且依賴的包里面有go.mod,直接走$GOPATH/pkg/mod
  • 沒有vendor,且依賴的包里面都沒有go.mod,直接走$GOPATH/src (待驗證)
  • 有vendor,也沒有用,只要依賴的包里面有go.mod,還是走$GOPATH/pkg/mod
  • 有vendor,且依賴的包里面都沒有go.mod,走vendor (待驗證)

3.3 有go.mod 且項目不在$GOPATH/src下

  • 有vendor, 則讀取vendor的外部引入包
  • 沒有vendor則讀取$GOPATH/pkg/mod里面的外部引入包

3.4 有go.mod 且項目在$GOPATH/src下

與上面的情況(有go.mod 且項目不在$GOPATH/src下)一致。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 最近由于換工作,開始交接工作。整理以前的工作內容,由于組內就我一個在做go和大數據。 所以開發沒有規劃,當時是怎么...
    若與閱讀 241,839評論 10 110
  • Go語言的包管理經過了多種工具的演變,上一節中我們通過配置GOPATH來存放源代碼進行包的管理,其實稱不上包管理,...
    whatiscoding閱讀 2,025評論 0 5
  • Go Module是Go會在1.12中正式推出的包管理機制。 Go mod 簡介 Golang一直存在一個被人詬病...
    會飛的鯰魚閱讀 47,938評論 1 14
  • 1. govendor簡介 golang工程的依賴包經常使用go get命令來獲取,例如:go get githu...
    葉揚風起閱讀 16,674評論 0 4
  • 16宿命:用概率思維提高你的勝算 以前的我是風險厭惡者,不喜歡去冒險,但是人生放棄了冒險,也就放棄了無數的可能。 ...
    yichen大刀閱讀 6,098評論 0 4