大家好,我是煎魚。
在 Go 項目的模塊管理中,先是 GOPATH,然后到廢棄。再到強推 Go modules,從被社區抗拒到 rsc 硬上弓。現在最新要了解的,就是工作區模式(workspace mode)。這是一個在 Go1.18 引入的重要特性。
之前一直沒提過,今天補全這塊的知識點。
在 Go1.11 起有了 Go modules 后,看起來 Go 模塊管理逐步按序有了約束、規范了起來。但也帶來了一些使用上的問題。
現實開發時,當我們需要對多個關聯模塊進行開發(修改)時,這個事情就麻煩了起來。我見過兩種方式。
1、第一種:直接在 go.mod 文件上配置 replace,配置到本地的開發目錄。這是最常見的方式。
// go.modreplace example.com/golang/text => "../eddycjy/golang/text"
這種做法經常會有人不小心提交到 Git 倉庫上。還挺折騰人的,一個不小心就為此 debug 了半天,或者發布部署一直卡著過不去。
2、第二種:直接在依賴模塊上編碼,編碼到一定的程度。才上傳 GitHub/GitLab。再去發布版本標簽再引用。這種用法比較少,只有模塊比較簡單且對程序比較自信的會這么干。(不推薦)
總的來講,就是有了 Go modules 后,多模塊間的依賴開發還是挺麻煩的。要經常 replace,有時候又會忘了刪。
在大家痛苦了許久后,Go1.18 時終于發布了工作區模式的方式,來優化這個用法和問題。
以下是 go work 的指令集:
go work <command> [arguments]
接下來我們快速應用 Go 工作區模式,讓大家有個直觀的了解。
需要注意,該特性需要確保 Go 版本 >= 1.18。
首先我們創建一個工作區,執行如下命令:
$ mkdir workspace-main && cd workspace-main $ go work init
執行完畢后會在該目錄下創建一個 go.work 文件,文件內容包含:
go 1.20
僅包含版本信息,因為當前是空白的工作區,只有初始化行為。
$ mkdir hello-world && cd hello-world$ go mod init example.com/hellogo: creating new go.mod: module example.com/hello
寫入代碼 hello.go:
package mainimport ( "fmt" "golang.org/x/example/hello/reverse")func main() { fmt.Println(reverse.String("Hello, 煎魚"))}
如果你這時候直接 go run。可能會出現如下報錯:
hello.go:6:5: no required module provides package golang.org/x/example/hello/reverse: go.mod file not found in current directory or any parent directory; see 'go help modules'
看著非常迷惑人,很多同學以為是環境變量 GO111MODULE 沒有設置為 on。其實是沒有將本模塊加入工作區中,導致運行錯誤。
所以可以看出來,在設計上是先有項目,再有工作區的路徑。也是相對符合的。
這時候需要回到工作區目錄 workspace-main。執行如下命令:
go work use ./hello-world
go.work 文件內會變成:
$ cat go.work go 1.20use ./hello-world
再運行程序:
$ go run hello-world/hello.go 魚煎 ,olleH
一切正常。
這時候我們有了一個實際的訴求,我們希望 golang.org/x/example/hello 改一下這個 SDK 庫。
如果是以前的話,我們需要寫 replace 來解決。現在的話可以用工作區模式來完成這個訴求。
我們先需要回到工作區根目錄 workspace-main 下,拉取這個 SDK 庫到工作區中:
git clone https://go.googlesource.com/example
再將其引入項目的工作區中:
go work use ./example/hello
go.work 文件會變成:
go 1.20use ( ./example/hello ./hello-world)
這里需要注意,go work 以 go.mod 為單位。如果你直接引入 ./example。是無法對 ./example/hello 的 module 起效果的。
在引入成功后,我們回到 ./example/hello 目錄下的 reverse.go 文件,新增一個用于 Demo 的方法:
...func Hello() string { return "煎魚,你好!"}
再到 hello 項目中,新增調用:
package mainimport ( "fmt" "golang.org/x/example/hello/reverse")func main() { fmt.Println(reverse.String("Hello, 煎魚")) fmt.Println(reverse.Hello())}
輸出結果:
魚煎 ,olleH煎魚,你好
一切正常。滿足不添加 replace 的要求,也使用了 go.work,不用擔心把 replace 不小心提交到 Git 倉庫中。
另外 Go 工作區中的項目在進行編譯時,也是引用所配置好的工作區內的模塊。而不是單單只針對開發階段的 go run,也可以在產線上去使用,編譯成二進制去應用和部署。
我們已經對 Go 的工作區模式有了一定的了解,其使用場景聚焦在如下:
今天我們快速了解了 Go 工作區模式(workspace mode)的背景、使用、場景。這對于解決項目中多模塊依賴有著一定的作用,可以不再需要去 go.mod 里 replace,算是給了一個規范化的解決方案。
但在實際應用中,我們會發現工作區模式的便利度,其實不太高。可能依賴模塊數量少時,還不如 replace 一把梭來得快。
另外目前階段的使用宣傳還是做得比較弱的,前兩天問了一圈,還真有一些同學不知道,也沒有用過的。
本文鏈接:http://www.tebozhan.com/showinfo-26-11897-0.html快速掌握 Go 工作區模式
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: 如何快速使用Docker部署我們的微服務