使用 Go 模塊

簡介

Go 終於要有本身的模塊了, 之前只有包, 而模塊是包的上一級.git

如下是閱讀官網上的兩篇文章的總結.github

使用 Go 模塊

一個模塊是存儲在文件樹中的一系列的 Go 包的集合, 根目錄有一個 go.mod 文件.golang

go.mod 文件定義了模塊的 module path, 這也是用於根目錄的導入路徑. 還定義了 dependency requirements, 這是構建須要的外部模塊.web

模塊的常見操做

建立一個新的模塊

$GOPATH/src 以外, 建立一個目錄, 並添加文件 hello.go:apache

package hello

func Hello() string {
    return "Hello, world."
}
複製代碼

添加一個測試文件, hello_test.go:json

package hello

import "testing"

func TestHello(t *testing.T) {
    want := "Hello, world."
    if got := Hello(); got != want {
        t.Errorf("Hello() = %q, want %q", got, want)
    }
}
複製代碼

到這裏, 該目錄包含一個包, 但還不是一個模塊, 由於尚未 go.mod 文件.緩存

若是在該目錄下運行 go test:安全

$ go test
PASS
ok      _/home/gopher/hello    0.020s
$
複製代碼

最後一行總結了全部的包的測試. 由於咱們在 $GOPATH 目錄外, 也在任何模塊以外, 全部 go 命令對當前目錄不知道任何導入路徑, 這會製造一個假的基於當前目錄名的模塊: _/home/gopher/hello.bash

如今, 使用 go mod init 將該目錄初始化爲一個模塊, 並從新運行 go test.併發

$ go mod init example.com/hello
go: creating new go.mod: module example.com/hello
$ go test
PASS
ok      example.com/hello    0.020s
$
複製代碼

這樣, 就建立一個 Go 模塊, 並運行了測試. 注意到, 模塊名字已經變成了 example.com/hello.

go mod init 命令產生了一個 go.mod 的文件.

$ cat go.mod
module example.com/hello

go 1.12
$
複製代碼

go.mod 文件只出如今模塊的根目錄. 在子目錄中的包的導入路徑爲 模塊路徑 加上 子目錄 路徑. 若是咱們建立了一個叫作 world 的子目錄, 這個包會自動被識別爲 模塊 example.com/hello的一部分, 它的導入路徑爲 example.com/hello/world.

添加一個依賴

Go 模塊的主要動力是提升代碼被其餘開發者做爲依賴的體驗.

更新 hello.go, 導入 rsc.io/quote 並使用它來實現 Hello 函數.

package hello

import "rsc.io/quote"

func Hello() string {
    return quote.Hello()
}
複製代碼

從新運行測試:

$ go test
go: finding rsc.io/quote v1.5.2
go: downloading rsc.io/quote v1.5.2
go: extracting rsc.io/quote v1.5.2
go: finding rsc.io/sampler v1.3.0
go: finding golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
go: downloading rsc.io/sampler v1.3.0
go: extracting rsc.io/sampler v1.3.0
go: downloading golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
go: extracting golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
PASS
ok      example.com/hello    0.023s
$
複製代碼

go 命令使用在 go.mod 中列出的特定依賴來解析導入. 當它遇到任何不在 go.mod 中的 import 導入的包時, go 命名會自動查找包含這個包的模塊, 並將它添加到 go.mod 文件中, 並使用最新的版本號.

$ cat go.mod
module example.com/hello

go 1.12

require rsc.io/quote v1.5.2
$
複製代碼

再次運行 go test 不會重複上面的過程, 由於 go.mod 是最新的, 並且下載的模塊已經緩存在本地了, 在 $GOPATH/pkg/mod目錄下.

添加一個直接的依賴一般會帶來一些間接的依賴, 命令 go list -m all 列出當前模塊和它的全部依賴.

$ go list -m all
example.com/hello
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
rsc.io/quote v1.5.2
rsc.io/sampler v1.3.0
$
複製代碼

一般第一行是主模塊, 下面都是它的依賴, 按模塊路徑排序.

golang.org/x/text 的版本是 v0.0.0-20170915032832-14c0d48ead0c, 這是一個 僞版本(pseudo-version), 這是 go 命令對沒有標籤的提交的版本語法.

除了 go.mod 以外, go 命令還維護了一個叫作 go.sum 的文件, 包含每個特定版本的模塊的內容的加密哈希.

$ cat go.sum
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZO...
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:Nq...
rsc.io/quote v1.5.2 h1:w5fcysjrx7yqtD/aO+QwRjYZOKnaM9Uh2b40tElTs3...
rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPX...
rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/Q...
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9...
$
複製代碼

go 命令經過使用 go.sum 文件來將來的下載和第一次下載同樣, 有相同的 bit. 保證你的項目依賴的模塊不會發生意外的變化. 這兩個文件 go.modgo.sum 都應該保存在版本控制之中.

升級依賴

使用 Go 模塊, 版本號使用語義版本標籤. 一個語義版本有三個部分: 主版本, 次版本, 補丁版本.

由於前面經過 go list -m all 看到 golang.org/x/text 使用了一個未標記的版本, 讓咱們升級到最新的版本, 並測試一切都正常.

$ go get golang.org/x/text
go: finding golang.org/x/text v0.3.0
go: downloading golang.org/x/text v0.3.0
go: extracting golang.org/x/text v0.3.0
$ go test
PASS
ok      example.com/hello    0.013s
$
複製代碼

一切正常, 從新看看 go list -m al 的輸出, 以及 go.mod 文件.

$ go list -m all
example.com/hello
golang.org/x/text v0.3.0
rsc.io/quote v1.5.2
rsc.io/sampler v1.3.0
$ cat go.mod
module example.com/hello

go 1.12

require (
    golang.org/x/text v0.3.0 // indirect
    rsc.io/quote v1.5.2
)
$
複製代碼

golang.org/x/text 包已經升級到最新版本了. go.mod 文件也更新了. indirect 註釋表示這不是一個直接被該模塊使用的依賴, 而是間接依賴.

讓咱們試圖更新 rsc.io/sampler 的次要版本, 使用相同的方式, 並運行測試:

$ go get rsc.io/sampler
go: finding rsc.io/sampler v1.99.99
go: downloading rsc.io/sampler v1.99.99
go: extracting rsc.io/sampler v1.99.99
$ go test
--- FAIL: TestHello (0.00s)
    hello_test.go:8: Hello() = "99 bottles of beer on the wall, 99 bottles of beer, ...", want "Hello, world."
FAIL
exit status 1
FAIL    example.com/hello    0.014s
$
複製代碼

測試失敗了, 這個版本不兼容咱們的用例. 看一看這個模塊有哪些版本:

$ go list -m -versions rsc.io/sampler
rsc.io/sampler v1.0.0 v1.2.0 v1.2.1 v1.3.0 v1.3.1 v1.99.99
$
複製代碼

換個版本試試, 咱們已經使用 1.3.0 了, 或許 1.3.1 能夠兼容.

$ go get rsc.io/sampler@v1.3.1
go: finding rsc.io/sampler v1.3.1
go: downloading rsc.io/sampler v1.3.1
go: extracting rsc.io/sampler v1.3.1
$ go test
PASS
ok      example.com/hello    0.022s
$
複製代碼

經過在 go get 中指明版本號, 默認是 @latest.

添加對新的主版本的依賴

添加一個新的功能, 修改 hello.go 文件:

package hello

import (
    "rsc.io/quote"
    quoteV3 "rsc.io/quote/v3"
)

func Hello() string {
    return quote.Hello()
}

func Proverb() string {
    return quoteV3.Concurrency()
}
複製代碼

而後添加一個新的測試, 在 hello_test.go 中:

func TestProverb(t *testing.T) {
    want := "Concurrency is not parallelism."
    if got := Proverb(); got != want {
        t.Errorf("Proverb() = %q, want %q", got, want)
    }
}
複製代碼

而後, 從新測試:

$ go test
go: finding rsc.io/quote/v3 v3.1.0
go: downloading rsc.io/quote/v3 v3.1.0
go: extracting rsc.io/quote/v3 v3.1.0
PASS
ok      example.com/hello    0.024s
$
複製代碼

注意到, 咱們的模塊如今依賴 rsc.io/quotersc.io/quote/v3.

$ go list -m rsc.io/q...
rsc.io/quote v1.5.2
rsc.io/quote/v3 v3.1.0
$
複製代碼

每個 GO 模塊的主要版本, 都會使用一個不一樣的路徑: 從 v2 開始, 路徑必須以主版本號結尾. 好比 rsc.io/quote 的 v3 版本, 再也不是 rsc.io/quote, 而是獨立的名字 rsc.io/quote/v3. 這種用法叫作 語義導入版本化, 它給了不兼容的包(不一樣主版本的包)一個不一樣的名字.

go 命令容許構建包含任何特定模塊路徑的至多一個版本, 意味着每個主版本最多一個路徑: 一個 rsc.io/quote, 一個 rsc.io/quote/v2, 一個 rsc.io/quote/v3等等. 這給予了模塊做者一個清晰的規則, 一個模塊路徑是否可能出現副本: 一個程序不可能同時使用 rsc.io/quote v1.5.2rsc.io/quote v1.6.0. 同時, 一個模塊的不一樣主版本容許共存, 能幫助模塊的消費者能夠漸進地升級到新的主版本上.

在這個例子中, 咱們想要使用 rsc/quote/v3 v3.1.0 中的 quote.Concurrency, 但咱們還沒 作好準備遷移對 rsc.io/quote v1.5.2 的使用.

在大型程序或代碼庫中, 逐步遷移的能力尤爲重要.

升級依賴到新的主版本

讓咱們繼續完成遷移, 開始只使用 rsc.io/quote/v3. 由於主版本的改變, 咱們預計到某些 APIs 可能已經被移除, 重命名, 或者以其餘不兼容的方式改變了.

經過閱讀文檔, 咱們發現 Hello 已經變成了 HelloV3:

$ go doc rsc.io/quote/v3
package quote // import "rsc.io/quote/v3"

Package quote collects pithy sayings.

func Concurrency() string
func GlassV3() string
func GoV3() string
func HelloV3() string
func OptV3() string
$
複製代碼

咱們經過升級將 hello.go 中的 quote.Hello() 改變爲 quoteV3.HelloV3().

package hello

import quoteV3 "rsc.io/quote/v3"

func Hello() string {
    return quoteV3.HelloV3()
}

func Proverb() string {
    return quoteV3.Concurrency()
}
複製代碼

在這個節點上, 咱們無需重命名導入了, 因此能夠這樣作:

package hello

import "rsc.io/quote/v3"

func Hello() string {
    return quote.HelloV3()
}

func Proverb() string {
    return quote.Concurrency()
}
複製代碼

從新運行測試, 一切正常.

移除未使用的依賴

咱們已經移除了對 rsc.io/quote 的使用, 但它依然出如今 go list -m allgo.mod 文件中.

爲何? 由於 go buildgo test 能夠輕易告訴咱們某些東西丟失了, 須要添加, 但沒法告訴咱們某些東西能夠安全地被移除.

移除一個依賴, 只有在檢查過模塊中的全部包, 和這些包全部可能的構建標籤組合 以後才能肯定. 一個普通的構建命令是不會加載這些信息的, 因此它不能安全地移除依賴.

go mod tidy 能夠清除這些未使用的包.

結論

在 Go 中 Go 模塊是依賴管理的將來. 模塊功能在全部支持的 Go 版本中是可用的了(GO 1.11 以後).

總結一下使用 Go 模塊的工做流:

  • go mod init 建立一個新的模塊, 初始化 go.mod 文件
  • go build, go test 和其餘的包構建命令會添加必要的依賴到 go.mod 文件中
  • go list -m all 打印出當前模塊的依賴
  • go get 改變一個依賴的必要版本
  • go mod tidy 移除未使用的依賴

遷移到 Go 模塊

Go 項目有各式各樣的依賴管理策略. Vendoring 工具, 好比 dep 或 glide 是 很是流行的, 但它們在行爲上很是不一樣, 且不能很好地兼容. 一些項目在 Git 倉庫中存儲它們的整個 GOPATH 目錄. 其餘一些可能僅依賴 go get 並指望在 GOPATH 中安裝最新的依賴.

Go 的模塊系統, 在 Go 1.11 中引入, 提供了一個基於 go 命令的官方依賴解決方案.

下面主要講述了這個工具, 以及將一個項目轉變爲模塊的技術.

注意: 若是你的項目已經在版本 2.0.0 或以上, 當你添加一個 go.mod 文件時, 須要升級你的模塊路徑.

遷移你的項目到 Go 模塊

一個即將轉換到 Go 模塊的項目可能處於下面三種狀況下:

  • 一個全新的 Go 項目
  • 一個使用依賴管理器的 Go 項目
  • 一個沒有任何依賴管理器的 Go 項目

這裏將討論後面兩種狀況.

已有依賴管理器

轉換一個已經有依賴管理器的項目, 使用下面的命令:

$ git clone https://github.com/my/project
[...]
$ cd project
$ cat Godeps/Godeps.json
{
    "ImportPath": "github.com/my/project",
    "GoVersion": "go1.12",
    "GodepVersion": "v80",
    "Deps": [
        {
            "ImportPath": "rsc.io/binaryregexp",
            "Comment": "v0.2.0-1-g545cabd",
            "Rev": "545cabda89ca36b48b8e681a30d9d769a30b3074"
        },
        {
            "ImportPath": "rsc.io/binaryregexp/syntax",
            "Comment": "v0.2.0-1-g545cabd",
            "Rev": "545cabda89ca36b48b8e681a30d9d769a30b3074"
        }
    ]
}
$ go mod init github.com/my/project
go: creating new go.mod: module github.com/my/project
go: copying requirements from Godeps/Godeps.json
$ cat go.mod
module github.com/my/project

go 1.12

require rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca
$
複製代碼

go mod init 會建立一個新的 go.mod 文件, 並自動導入依賴, 從 Godeps.json, Gopkg.lock其餘支持的格式中.

go mod init 的參數是模塊路徑, 模塊從哪裏發現的位置.

在繼續以前, 先運行 go buildgo test. 後續的步驟可能會修改你的 go.mod 文件, 若是你想要迭代更新, 這是最接近你的模塊依賴規範的 go.mod 文件.

$ go mod tidy
go: downloading rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca
go: extracting rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca
$ cat go.sum
rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca h1:FKXXXJ6G2bFoVe7hX3kEX6Izxw5ZKRH57DFBJmHCbkU=
rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
$
複製代碼

go mod tidy 查找在你的模塊中, 確實被導入的包. 它會爲不在任何已知模塊中的包添加模塊依賴, 並刪除任何沒有提供導入包的模塊. 若是一個模塊提供的包只被尚未遷移到模塊系統的項目使用, 這個模塊依賴會使用 // indirect 註釋標記.

當提交對 go.mod 的改動到版本控制中, 一個好習慣是先運行 go mod tidy.

最後, 檢查代碼構建成功, 並經過測試.

$ go build ./...
$ go test ./...
[...]
$
複製代碼

注意, 其餘的依賴管理器可能在我的包或者整個倉庫的級別上指定依賴關係, 而且一般沒法識別 go.mod 中指定的依賴. 所以, 你可能沒法得到 和之前同樣的每一個包的徹底相同的版本, 而且升級可能發生破壞性的變化. 所以, 經過審計生成的依賴來執行上面的命令很是重要.

運行下面的命令:

$ go list -m all
go: finding rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca
github.com/my/project
rsc.io/binaryregexp v0.2.1-0.20190524193500-545cabda89ca
$
複製代碼

並經過對比你的舊依賴管理文件來肯定選擇的版本是恰當的. 若是你發現一個版本不是你想要的, 能夠經過 go mod why -mgo mod graph 命令來發現爲何, 並使用 go get 升級或降級到正確的版本.

若是須要降級, go get 也可能會降級其餘依賴來知足最小兼容性.

$ go mod why -m rsc.io/binaryregexp
[...]
$ go mod graph | grep rsc.io/binaryregexp
[...]
$ go get rsc.io/binaryregexp@v0.2.0
$
複製代碼

沒有使用包管理器

對於沒有使用包管理器的 Go 項目, 從建立 go.mod 文件開始:

$ git clone https://go.googlesource.com/blog
[...]
$ cd blog
$ go mod init golang.org/x/blog
go: creating new go.mod: module golang.org/x/blog
$ cat go.mod
module golang.org/x/blog

go 1.12
$
複製代碼

沒有先前的依賴管理文件能夠參考, 因此 go mod init 會建立 一個只有 modulego 指令的 go.mod 文件. 在這個例子中, 咱們設置模塊路徑爲 golang.org/x/blog, 是由於 那是它的 自定義導入路徑. 用戶可能使用這個路徑導入包, 因此咱們必須當心對待, 不要改變它.

module 指令聲明瞭模塊路徑, go 指令聲明瞭用來兼容 這個模塊的 Go 語言版本.

如今, 運行 go mod tidy 添加依賴:

$ go mod tidy
go: finding golang.org/x/website latest
go: finding gopkg.in/tomb.v2 latest
go: finding golang.org/x/net latest
go: finding golang.org/x/tools latest
go: downloading github.com/gorilla/context v1.1.1
go: downloading golang.org/x/tools v0.0.0-20190813214729-9dba7caff850
go: downloading golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
go: extracting github.com/gorilla/context v1.1.1
go: extracting golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
go: downloading gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637
go: extracting gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637
go: extracting golang.org/x/tools v0.0.0-20190813214729-9dba7caff850
go: downloading golang.org/x/website v0.0.0-20190809153340-86a7442ada7c
go: extracting golang.org/x/website v0.0.0-20190809153340-86a7442ada7c
$ cat go.mod
module golang.org/x/blog

go 1.12

require (
    github.com/gorilla/context v1.1.1
    golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
    golang.org/x/text v0.3.2
    golang.org/x/tools v0.0.0-20190813214729-9dba7caff850
    golang.org/x/website v0.0.0-20190809153340-86a7442ada7c
    gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637
)
$ cat go.sum
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
git.apache.org/thrift.git v0.0.0-20181218151757-9b75e4fe745a/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
[...]
$
複製代碼

go mod tidy 爲全部在你的模塊中直接導入的包添加模塊依賴, 而且建立一個 go.sum 文件 保存每個庫在特定版本下的校驗和. 檢查是否經過構建和測試:

$ go build ./...
$ go test ./...
ok      golang.org/x/blog    0.335s
?       golang.org/x/blog/content/appengine    [no test files]
ok      golang.org/x/blog/content/cover    0.040s
?       golang.org/x/blog/content/h2push/server    [no test files]
?       golang.org/x/blog/content/survey2016    [no test files]
?       golang.org/x/blog/content/survey2017    [no test files]
?       golang.org/x/blog/support/racy    [no test files]
$
複製代碼

注意, 當 go mod tidy 添加一個依賴時, 它會添加這個模塊的最新版本. 若是你的 GOPATH 中包含了一箇舊版本的依賴, 那麼新版本可能會帶來 破壞性的變化, 你可能在 go mod tidy, go buildgo test 中 看到錯誤.

若是發生了這種事, 試着用 go get 降級版本, 或者將你的模塊兼容 每一個依賴的最新版本.

在模塊下進行測試

一些測試可能在遷移到 Go 模塊後須要調整.

若是一個測試須要在包目錄下寫入文件, 當這個包目錄位於模塊緩存中時可能失敗, 由於它是隻讀的. 在特定狀況下, 這可能致使 go test all 失敗. 測試應該複製它須要的文件並寫到到一個臨時目錄中.

若是一個測試依賴相對路徑(../package-in-another-module) 來定位並 讀取在另外一個包中的文件, 若是包在另外一個模塊中, 測試會失敗. 這個路徑會被定位在模塊緩存的版本化子目錄中, 或者一個被 replace 指令指定的路徑中.

在這種狀況下, 你可能須要複製測試輸入到你的模塊中, 或者將測試輸入 從原始文件轉爲嵌入到 .go 源文件的數據.

若是測試須要 go 命令在 GOPATH 模式下運行測試, 它可能失敗. 在這種狀況下, 你可能須要添加一個 go.mod 文件到要被測試的源代碼樹中, 或者明確地設置 GO111MODULE=off.

發佈一個版本

最終, 你應該爲你的模塊標記一個版本併發布. 若是你尚未發佈任何版本, 這是可選的, 可是沒有正式發佈的版本, 下游的使用者在特定的提交上使用 僞版本, 這可能更難以支持.

$ git tag v1.2.0
$ git push origin v1.2.0
複製代碼

你的新 go.mod 文件爲你的模塊定義了一個規範的導入路徑, 並添加了最低的依賴版本. 若是你的用戶已經使用正確的導入路徑, 你的依賴也沒有破壞性的改動, 那麼添加 go.mod 文件是向後兼容的. 但它是一個重大的改變, 可能暴露已存在的問題.

若是你已經現存的版本了, 你應該增長主版本號.

導入和規範模塊路徑

每個模塊在 go.mod 中聲明瞭它的模塊路徑. 引用模塊中的包的每一個 import 語句必須將模塊路徑做爲包路徑的前綴. 可是, go 命令可能遇到一個包含許多不一樣 遠程導入路徑 的倉庫. 舉個例子, golang.org/x/lintgithub.com/golang/lint 均可以 解析爲託管在 go.googlesource.com/lint 中的代碼倉庫. go.mod 文件包含的倉庫聲明爲 golang.org/x/lint, 因此只有這條路徑 對應了一個有效的模塊.

Go 1.4 提供了一個機制, 用於聲明規範的導入路徑, 經過 // import 註釋, 但包做者並不老是提供它們. 所以, 在模塊出現以前編寫的代碼可能使用了不規範的模塊導入路徑, 卻沒有由於路徑不匹配而出現錯誤. 當使用模塊後, 導入路徑必須匹配規範的模塊路徑, 因此你須要更新 import 語句. 舉個例子, 你可能須要將 import "github.com/golang/lint" 改成 import "golang.org/x/lint".

另外一個問題是, 對於主版本大於等於 2 的模塊, 模塊的規範路徑和它的存儲庫路徑不一致. 一個主版本大於 1 的 Go 模塊, 必須在它的模塊路徑以後加上主版本號做爲後綴. 好比版本 2.0.0 必須添加後綴 /v2. 可是 import 語句可能引用了 模塊中的包, 但沒有提供版本後綴. 舉個例子, 非模塊用戶在可能在版本 v2.0.1 中使用了 github.com/russross/blackfriday 而不是 github.com/russross/blackfriday/v2, 須要更新導入路徑包含後綴 /v2.

總結

對大多數用戶而言, 轉換爲 Go 模塊應該是一個簡單的過程. 由於非規範的導入路徑或者破壞性的依賴可能偶然致使出錯.

相關文章
相關標籤/搜索