Go 1.18 新特性多模組工作區教程-讓多模組開發變得簡單

link1st發表於2022-03-21

導讀

  • 隨著 2022 年 3 月 15 日 go 1.18 正式釋出,新版本除了對效能的提升之外,還引入了很多新功能,其中就有 go 期盼已久的功能泛型(Generics),同時還引入的多模組工作區(Workspaces)和模糊測試(Fuzzing)。
  • 關於泛型網上已經有很多介紹的教程了,這裡我介紹一個實用的功能,多模組工作區的使用方法和教程。
  • Go 多模組工作區能夠使開發者能夠更容易地同時處理多個模組的工作,如:

    方便進行依賴的程式碼除錯(打斷點、修改程式碼)、排查依賴程式碼 bug
    方便同時進行多個倉庫/模組並行開發除錯

目錄

多模組工作區

說明

  • go 使用的是多模組工作區,可以讓開發者更容易同時處理多個模組的開發。在 Go 1.17 之前,只能使用 go.mod replace 指令來實現,如果你正巧是同時進行多個模組的開發,使用它可能是很痛苦的。每次當你想要提交程式碼的時候,都不得不刪除掉 go.mod 中的 replace 才能使模組穩定的釋出版本。
  • 在使用 go 1.18 多模組工作區功能的時候,就使用這項工作變得簡單容易處理。下面我來介紹怎麼使用這一功能。
  • Go 多模組工作區文件、程式碼示例獲取地址 https://github.com/link1st/li...

使用條件

  • 首先 我們需要 go 1.18 或更高版本 go 安裝
# 檢視 go 版本
> go version
go version go1.18 darwin/amd64

go work 支援命令

  • 通常情況下,建議不要提交 go.work 檔案到 git 上,因為它主要用於原生程式碼開發。
  • 推薦在: $GOPATH 路徑下執行,生成 go.work 檔案
  • go work init 初始化工作區檔案,用於生成 go.work 工作區檔案

    初始化並寫入一個新的 go.work 到當前路徑下,可以指定需要新增的程式碼模組
    示例: go work init ./hello 將本地倉庫 hello 新增到工作區
    hello 倉庫必須是 go mod 依賴管理的倉庫(./hello/go.mod 檔案必須存在)
  • go work use 新增新的模組到工作區

    命令示例:
    go work use ./example 新增一個模組到工作區
    go work use ./example ./example1 新增多個模組到工作區
    go work use -r ./example 遞迴 ./example 目錄到當前工作區
    刪除命令使用 go work edit -dropuse=./example 功能
  • go work edit 用於編輯 go.work 檔案

    可以使用 edit 命令編輯和手動編輯 go.work 檔案效果是相同的
    示例:
    go work edit -fmt go.work 重新格式化 go.work 檔案
    go work edit -replace=github.com/link1st/example=./example go.work 替換程式碼模組
    go work edit -dropreplace=github.com/link1st/example 刪除替換程式碼模組
    go work edit -use=./example go.work 新增新的模組到工作區
    go work edit -dropuse=./example go.work 從工作區中刪除模組
  • go work sync 將工作區的構建列表同步到工作區的模組
  • go env GOWORK

    檢視環境變數,檢視當前工作區檔案路徑
    可以排查工作區檔案是否設定正確,go.work 路徑找不到可以使用 GOWORK 指定
> go env GOWORK
$GOPATH/src/link1st/link1st/workspaces/go.work

go.work 檔案結構

  • 檔案結構和 go.mod 檔案結構類似,支援 Go 版本號、指定工作區和需要替換的倉庫
  • 檔案結構示例:
go 1.18

use (
    ./hello
    ./example
)

replace (
    github.com/link1st/example => ./example1
)
use 指定使用的模組目錄
  • 可以使用 go work use hello 新增模組,也可以手動修改 go.work 工作區新增新的模組
  • 在工作區中新增了模組路徑,編譯的時候會自動使用 use 中的原生程式碼進行程式碼編譯,和 replaces 功能類似。
# 單模組結構
use ./hello

# 多模組結構
use (
    ./hello
    ./example
)
replaces 替換依賴倉庫地址
  • replaces 命令與 go.mod 指令相同,用於替換專案中依賴的倉庫地址
  • 需要注意的是 replacesuse 不能同時指定相同的本地路徑
同時指定報錯資訊:
go: workspace module github.com/link1st/example is replaced at all versions in the go.work file. To fix, remove the replacement from the go.work file or specify the version at which to replace the module.
  • 錯誤示例
同時在 usereplace 指定相同的本地路徑
go 1.18

use (
    ./hello
    ./example
)

replace (
    github.com/link1st/example => ./example
)
go.work 檔案優先順序高於 go.mod 中定義
  • 在同時使用 go.workgo.mod replace 功能的的時候分別指定不同的程式碼倉庫路徑,go.work 優先順序高於 go.mod 中定義
go.mod 中定義替換為本地倉庫 example
replace (
    github.com/link1st/example => ./example1
)
go.work 中定義替換為本地倉庫 example1
replace (
    github.com/link1st/example => ./example1
)
  • 在程式碼構建時候使用的是 go.work 指定的 example1 倉庫的程式碼,go.work 優先順序別更高

如何使用

  • 在 Go 1.18 go rungo build 都會預設使用工作區功能
  • GOWORK 也可以指定配置 go.work 檔案位置
export GOWORK="~/go/src/test/go.18/workspace/go.work"

如何禁用工作區

  • Go 全域性變數 GOWORK 設定 off 則可以禁用工作區功能

    export GOWORK=off

開發流程演示

  • 演示如何使用多模組工作區功能。在現在微服務盛行的年代,一個人會維護多個程式碼倉庫,很多的時候是多個倉庫進行同時開發
  • 假設我們現在進行 hello 倉庫開發,實現的功能是,實現將輸入的字串反轉並輸出,字串反轉功能依賴於 github.com/link1st/example (下文統稱 example)公共倉庫實現
  • 新建 hello 專案
mkdir hello
cd hello
# 程式碼倉庫啟動 go mod 依賴管理,生成 go.mod 檔案
go mod init github.com/link1st/link1st/workspaces/hello
# 下載依賴包
go get github.com/link1st/example
# 編寫 main 檔案
vim main.go
  • main.go 程式碼
// Package main main 檔案,go 多模組工作區演示程式碼
// 實現將輸入的字串反轉輸出並輸出
package main

import (
    "flag"
    "fmt"

    "github.com/link1st/example/stringutil"
)

var (
    str = ""
)

func init() {
    flag.StringVar(&str, "str", str, "輸入字元")
    flag.Parse()
}

func main() {
    if str == "" {
        fmt.Println("示例: go run main.go -str hello")
        fmt.Println("str 引數必填")
        flag.Usage()
        return
    }

    // 呼叫公共倉庫,進行字串反轉
    str = stringutil.Reversal(str)
    // 輸出反轉後的字串
    fmt.Println(str)
    return
}

  • 執行程式碼 go run main.go -str "hello world"go run github.com/link1st/link1st/workspaces/hello -str "hello world" 可以看到輸出了 hello world 反轉以後的字串
> go run main.go -str "hello world"
dlrow olleh
  • 到這裡,最初的功能已經完成,但是後續需求變動,不僅需要輸出反轉以後的字串,還需要將字串大寫
  • 我們則需要去 example 倉庫中新增開發 將字串大寫的功能
# 回到工作根目錄,將 common 程式碼下載到本地進行新增新的功能
# 下載依賴的 example 包
git clone git@github.com:link1st/example.git
# 在 example 包中新增 字串大學的功能
  • vim example/stringutil/to_upper.go 程式碼如下
// Package stringutil stringutil
package stringutil

import (
    "unicode"
)

// ToUpper 將字串進行大寫
func ToUpper(s string) string {
    r := []rune(s)
    for i := range r {
        r[i] = unicode.ToUpper(r[i])
    }
    return string(r)
}
  • 由於程式碼還在本地除錯,未提交 git 倉庫中,這個時候就需要用到 Go 多模組工作區的功能了。
  • 進入專案根目錄,初始化我們現在正在開發的模組
# 初始化 go.work 檔案
go work init  ./hello ./example
# 檢視 go.work 檔案內容
cat go.work
  • 檔案結構如下
go 1.18

use (
    ./example
    ./hello
)
  • 回到 hello 專案,vim main.go 將字串大寫的功能新增上。
func main() {
    ...

    // 呼叫公共倉庫,進行字串反轉
    str = stringutil.Reversal(str)
    // 增加字元大寫的功能
    str = stringutil.ToUpper(str)
    // 輸出反轉後的字串
    fmt.Println(str)
    
    ...
}
  • 執行程式碼

    可以看到輸出了反轉並 大寫 的字串,大寫的函式功能只在本地,未提交到 git 上,這樣我們就實現了可以同時在兩個模組上並行開發
go run main.go -str "hello world"
DLROW OLLEH
  • 到這裡,演示的程式碼已經全部完成

總結

  • 使用 Go 多模組工作區的功能,可以讓我們輕鬆在多個模組之間切換工作,更能適應現代微服務架構開發。

參考文獻

Go 1.18 新特性多模組工作區教程

Go 1.18 is released!

Tutorial: Getting started with multi-module workspaces

go-1.18-features

相關文章