<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                [TOC] ## 8、精通Golang項目依賴Go modules ### 一、什么是Go Modules? Go modules 是 Go 語言的依賴解決方案,發布于 Go1.11,成長于 Go1.12,豐富于 Go1.13,正式于 Go1.14 推薦在生產上使用。 Go moudles 目前集成在 Go 的工具鏈中,只要安裝了 Go,自然而然也就可以使用 Go moudles 了,而 Go modules 的出現也解決了在 Go1.11 前的幾個常見爭議問題: 1. Go 語言長久以來的依賴管理問題。 2. “淘汰”現有的 GOPATH 的使用模式。 3. 統一社區中的其它的依賴管理工具(提供遷移功能)。 ### 二、GOPATH的工作模式 Go Modoules的目的之一就是淘汰GOPATH, 那么GOPATH是個什么? 為什么在 Go1.11 前就使用 GOPATH,而 Go1.11 后就開始逐步建議使用 Go modules,不再推薦 GOPATH 的模式了呢? #### (1) Wait is GOPATH? ```bash $ go env GOPATH="/home/itheima/go" ... ``` 我們輸入`go env`命令行后可以查看到 GOPATH 變量的結果,我們進入到該目錄下進行查看,如下: ```bash go ├── bin ├── pkg └── src ├── github.com ├── golang.org ├── google.golang.org ├── gopkg.in .... ``` GOPATH目錄下一共包含了三個子目錄,分別是: - bin:存儲所編譯生成的二進制文件。 - pkg:存儲預編譯的目標文件,以加快程序的后續編譯速度。 - src:存儲所有`.go`文件或源代碼。在編寫 Go 應用程序,程序包和庫時,一般會以`$GOPATH/src/github.com/foo/bar`的路徑進行存放。 因此在使用 GOPATH 模式下,我們需要將應用代碼存放在固定的`$GOPATH/src`目錄下,并且如果執行`go get`來拉取外部依賴會自動下載并安裝到`$GOPATH`目錄下。 #### (2) GOPATH模式的弊端 在 GOPATH 的 `$GOPATH/src` 下進行 `.go` 文件或源代碼的存儲,我們可以稱其為 GOPATH 的模式,這個模式擁有一些弊端. * **A. 無版本控制概念.** 在執行`go get`的時候,你無法傳達任何的版本信息的期望,也就是說你也無法知道自己當前更新的是哪一個版本,也無法通過指定來拉取自己所期望的具體版本。 - **B.無法同步一致第三方版本號.** 在運行 Go 應用程序的時候,你無法保證其它人與你所期望依賴的第三方庫是相同的版本,也就是說在項目依賴庫的管理上,你無法保證所有人的依賴版本都一致。 - **C.無法指定當前項目引用的第三方版本號. ** 你沒辦法處理 v1、v2、v3 等等不同版本的引用問題,因為 GOPATH 模式下的導入路徑都是一樣的,都是`github.com/foo/bar`。 ### 三、Go Modules模式 我們接下來用Go Modules的方式創建一個項目, 建議為了與GOPATH分開,不要將項目創建在`GOPATH/src`下. #### (1) go mod命令 | 命令 | 作用 | | :-------------- | :------------------------------- | | go mod init | 生成 go.mod 文件 | | go mod download | 下載 go.mod 文件中指明的所有依賴 | | go mod tidy | 整理現有的依賴 | | go mod graph | 查看現有的依賴結構 | | go mod edit | 編輯 go.mod 文件 | | go mod vendor | 導出項目所有的依賴到vendor目錄 | | go mod verify | 校驗一個模塊是否被篡改過 | | go mod why | 查看為什么需要依賴某模塊 | #### (2) go mod環境變量 可以通過 `go env` 命令來進行查看 ```bash $ go env GO111MODULE="auto" GOPROXY="https://proxy.golang.org,direct" GONOPROXY="" GOSUMDB="sum.golang.org" GONOSUMDB="" GOPRIVATE="" ... ``` ##### GO111MODULE Go語言提供了 `GO111MODULE `這個環境變量來作為 Go modules 的開關,其允許設置以下參數: - auto:只要項目包含了 go.mod 文件的話啟用 Go modules,目前在 Go1.11 至 Go1.14 中仍然是默認值。 - on:啟用 Go modules,推薦設置,將會是未來版本中的默認值。 - off:禁用 Go modules,不推薦設置。 可以通過來設置 ```bash $ go env -w GO111MODULE=on ``` ##### GOPROXY 這個環境變量主要是用于設置 Go 模塊代理(Go module proxy),其作用是用于使 Go 在后續拉取模塊版本時直接通過鏡像站點來快速拉取。 GOPROXY 的默認值是:`https://proxy.golang.org,direct` `proxy.golang.org`國內訪問不了,需要設置國內的代理. * 阿里云 https://mirrors.aliyun.com/goproxy/ * 七牛云 https://goproxy.cn,direct 如: ```bash $ go env -w GOPROXY=https://goproxy.cn,direct ``` GOPROXY 的值是一個以英文逗號 “,” 分割的 Go 模塊代理列表,允許設置多個模塊代理,假設你不想使用,也可以將其設置為 “off” ,這將會禁止 Go 在后續操作中使用任何 Go 模塊代理。 如: ```bash $ go env -w GOPROXY=https://goproxy.cn,https://mirrors.aliyun.com/goproxy/,direct ``` > direct 而在剛剛設置的值中,我們可以發現值列表中有 “direct” 標識,它又有什么作用呢? 實際上 “direct” 是一個特殊指示符,用于指示 Go 回源到模塊版本的源地址去抓取(比如 GitHub 等),場景如下:當值列表中上一個 Go 模塊代理返回 404 或 410 錯誤時,Go 自動嘗試列表中的下一個,遇見 “direct” 時回源,也就是回到源地址去抓取,而遇見 EOF 時終止并拋出類似 “invalid version: unknown revision...” 的錯誤。 ##### GOSUMDB 它的值是一個 Go checksum database,用于在拉取模塊版本時(無論是從源站拉取還是通過 Go module proxy 拉取)保證拉取到的模塊版本數據未經過篡改,若發現不一致,也就是可能存在篡改,將會立即中止。 GOSUMDB 的默認值為:`sum.golang.org`,在國內也是無法訪問的,但是 GOSUMDB 可以被 Go 模塊代理所代理(詳見:Proxying a Checksum Database)。 因此我們可以通過設置 GOPROXY 來解決,而先前我們所設置的模塊代理 `goproxy.cn` 就能支持代理 `sum.golang.org`,所以這一個問題在設置 GOPROXY 后,你可以不需要過度關心。 另外若對 GOSUMDB 的值有自定義需求,其支持如下格式: - 格式 1:`<SUMDB_NAME>+<PUBLIC_KEY>`。 - 格式 2:`<SUMDB_NAME>+<PUBLIC_KEY> <SUMDB_URL>`。 也可以將其設置為“off”,也就是禁止 Go 在后續操作中校驗模塊版本。 ##### GONOPROXY/GONOSUMDB/GOPRIVATE 這三個環境變量都是用在當前項目依賴了私有模塊,例如像是你公司的私有 git 倉庫,又或是 github 中的私有庫,都是屬于私有模塊,都是要進行設置的,否則會拉取失敗。 更細致來講,就是依賴了由 GOPROXY 指定的 Go 模塊代理或由 GOSUMDB 指定 Go checksum database 都無法訪問到的模塊時的場景。 而一般**建議直接設置 GOPRIVATE,它的值將作為 GONOPROXY 和 GONOSUMDB 的默認值,所以建議的最佳姿勢是直接使用 GOPRIVATE**。 并且它們的值都是一個以英文逗號 “,” 分割的模塊路徑前綴,也就是可以設置多個,例如: ```bash $ go env -w GOPRIVATE="git.example.com,github.com/eddycjy/mquote" ``` 設置后,前綴為 git.xxx.com 和 github.com/eddycjy/mquote 的模塊都會被認為是私有模塊。 如果不想每次都重新設置,我們也可以利用通配符,例如: ```bash $ go env -w GOPRIVATE="*.example.com" ``` 這樣子設置的話,所有模塊路徑為 example.com 的子域名(例如:git.example.com)都將不經過 Go module proxy 和 Go checksum database,**需要注意的是不包括 example.com 本身**。 ### 四、使用Go Modules初始化項目 #### (1) 開啟Go Modules ```bash $ go env -w GO111MODULE=on ``` 又或是可以通過直接設置系統環境變量(寫入對應的~/.bash_profile 文件亦可)來實現這個目的: ```bash $ export GO111MODULE=on ``` #### (2) 初始化項目 創建項目目錄 ```bash $ mkdir -p $HOME/aceld/modules_test $ cd $HOME/aceld/modules_test ``` 執行Go modules 初始化 ```bash $ go mod init github.com/aceld/modules_test go: creating new go.mod: module github.com/aceld/modules_test ``` ? 在執行 `go mod init` 命令時,我們指定了模塊導入路徑為 `github.com/aceld/modules_test`。接下來我們在該項目根目錄下創建 `main.go` 文件,如下: ```go package main import ( "fmt" "github.com/aceld/zinx/znet" "github.com/aceld/zinx/ziface" ) //ping test 自定義路由 type PingRouter struct { znet.BaseRouter } //Ping Handle func (this *PingRouter) Handle(request ziface.IRequest) { //先讀取客戶端的數據 fmt.Println("recv from client : msgId=", request.GetMsgID(), ", data=", string(request.GetData())) //再回寫ping...ping...ping err := request.GetConnection().SendBuffMsg(0, []byte("ping...ping...ping")) if err != nil { fmt.Println(err) } } func main() { //1 創建一個server句柄 s := znet.NewServer() //2 配置路由 s.AddRouter(0, &PingRouter{}) //3 開啟服務 s.Serve() } ``` OK, 我們先不要關注代碼本身,我們看當前的main.go也就是我們的`aceld/modules_test`項目,是依賴一個叫`github.com/aceld/zinx`庫的. `znet`和`ziface`只是`zinx`的兩個模塊. 接下來我們在`$HOME/aceld/modules_test`,本項目的根目錄執行 ```bash $ go get github.com/aceld/zinx/znet go: downloading github.com/aceld/zinx v0.0.0-20200221135252-8a8954e75100 go: found github.com/aceld/zinx/znet in github.com/aceld/zinx v0.0.0-20200221135252-8a8954e75100 ``` 我們會看到 我們的`go.mod`被修改,同時多了一個`go.sum`文件. #### (3) 查看go.mod文件 > aceld/modules_test/go.mod ```go module github.com/aceld/modules_test go 1.14 require github.com/aceld/zinx v0.0.0-20200221135252-8a8954e75100 // indirect ``` 我們來簡單看一下這里面的關鍵字 `module`: 用于定義當前項目的模塊路徑 `go`:標識當前Go版本.即初始化版本 `require`: 當前項目依賴的一個特定的必須版本 `// indirect`: 示該模塊為間接依賴,也就是在當前應用程序中的 import 語句中,并沒有發現這個模塊的明確引用,有可能是你先手動 `go get` 拉取下來的,也有可能是你所依賴的模塊所依賴的.我們的代碼很明顯是依賴的`"github.com/aceld/zinx/znet"`和`"github.com/aceld/zinx/ziface"`,所以就間接的依賴了`github.com/aceld/zinx` #### (4) 查看go.sum文件 在第一次拉取模塊依賴后,會發現多出了一個 go.sum 文件,其詳細羅列了當前項目直接或間接依賴的所有模塊版本,并寫明了那些模塊版本的 SHA-256 哈希值以備 Go 在今后的操作中保證項目所依賴的那些模塊版本不會被篡改。 ```bash github.com/aceld/zinx v0.0.0-20200221135252-8a8954e75100 h1:Ez5iM6cKGMtqvIJ8nvR9h74Ln8FvFDgfb7bJIbrKv54= github.com/aceld/zinx v0.0.0-20200221135252-8a8954e75100/go.mod h1:bMiERrPdR8FzpBOo86nhWWmeHJ1cCaqVvWKCGcDVJ5M= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= ``` 我們可以看到一個模塊路徑可能有如下兩種: h1:hash情況 ```bash github.com/aceld/zinx v0.0.0-20200221135252-8a8954e75100 h1:Ez5iM6cKGMtqvIJ8nvR9h74Ln8FvFDgfb7bJIbrKv54= ``` go.mod hash情況 ```bash github.com/aceld/zinx v0.0.0-20200221135252-8a8954e75100/go.mod h1:bMiERrPdR8FzpBOo86nhWWmeHJ1cCaqVvWKCGcDVJ5M= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= ``` h1 hash 是 Go modules 將目標模塊版本的 zip 文件開包后,針對所有包內文件依次進行 hash,然后再把它們的 hash 結果按照固定格式和算法組成總的 hash 值。 而 h1 hash 和 go.mod hash 兩者,要不就是同時存在,要不就是只存在 go.mod hash。那什么情況下會不存在 h1 hash 呢,就是當 Go 認為肯定用不到某個模塊版本的時候就會省略它的 h1 hash,就會出現不存在 h1 hash,只存在 go.mod hash 的情況。 ### 五、修改模塊的版本依賴關系 ? 為了作嘗試,假定我們現在都zinx版本作了升級, 由`zinx v0.0.0-20200221135252-8a8954e75100` 升級到 `zinx v0.0.0-20200306023939-bc416543ae24` (注意zinx是一個沒有打版本tag打第三方庫,如果有的版本號是有tag的,那么可以直接對應v后面的版本號即可) ? 那么,我們是怎么知道zinx做了升級呢, 我們又是如何知道的最新的`zinx`版本號是多少呢? ? 先回到`$HOME/aceld/modules_test`,本項目的根目錄執行 ```bash $ go get github.com/aceld/zinx/znet go: downloading github.com/aceld/zinx v0.0.0-20200306023939-bc416543ae24 go: found github.com/aceld/zinx/znet in github.com/aceld/zinx v0.0.0-20200306023939-bc416543ae24 go: github.com/aceld/zinx upgrade => v0.0.0-20200306023939-bc416543ae24 ``` 這樣我們,下載了最新的zinx, 版本是`v0.0.0-20200306023939-bc416543ae24` ? 然后,我么看一下go.mod ```go module github.com/aceld/modules_test go 1.14 require github.com/aceld/zinx v0.0.0-20200306023939-bc416543ae24 // indirect ``` 我們會看到,當我們執行`go get` 的時候, 會自動的將本地將當前項目的`require`更新了.變成了最新的依賴. 好了, 現在我們就要做另外一件事,就是,我們想用一個舊版本的zinx. 來修改當前`zinx`模塊的依賴版本號. 目前我們在`$GOPATH/pkg/mod/github.com/aceld`下,已經有了兩個版本的zinx庫 ```bash /go/pkg/mod/github.com/aceld$ ls zinx@v0.0.0-20200221135252-8a8954e75100 zinx@v0.0.0-20200306023939-bc416543ae24 ``` ? 目前,我們`/aceld/modules_test`依賴的是`zinx@v0.0.0-20200306023939-bc416543ae24` 這個是最新版, 我們要改成之前的版本`zinx@v0.0.0-20200306023939-bc416543ae24`. ? 回到`/aceld/modules_test`項目目錄下,執行 ```bash $ go mod edit -replace=zinx@v0.0.0-20200306023939-bc416543ae24=zinx@v0.0.0-20200221135252-8a8954e75100 ``` ? 然后我們打開go.mod查看一下 ```go module github.com/aceld/modules_test go 1.14 require github.com/aceld/zinx v0.0.0-20200306023939-bc416543ae24 // indirect replace zinx v0.0.0-20200306023939-bc416543ae24 => zinx v0.0.0-20200221135252-8a8954e75100 ``` ? 這里出現了`replace`關鍵字.用于將一個模塊版本替換為另外一個模塊版本。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看