Go Modules详解

modulesGo 1.11版本提出的一个依赖包管理系统。

自己如何创建module

之前在Go1.1.1新功能module的介绍及使用文中中介绍了module功能,以及如何使用别人已经制作好的module。这一节我们来看看如何自己创建module来让别人使用。

  1. 首先创建一个包,命名为testmod。但是需要注意:testmod目录必须在$GOPATH目录之外。默认情况下,$GOPATH目录下module功能是无法使用的。

  2. 然后进入testmod目录,创建一个简单的testmod.go文件。

package testmod

import "fmt"

// SayHello returns a friendly greeting
func SayHello(name string) string {
    return fmt.Sprintf("Hello, %s", name)
}

目前testmod包不能称为一个module,现在我们来改变它。在命令行执行下面的命令(前提是你有github仓库或者可以存放你代码的仓库),下面go命令中的github.com/benben2015/testmod是我为testmod创建的仓库地址。

go mod init github.com/benben2015/testmod

# go: creating new go.mod: module github.com/benben2015/testmod

上面将会在testmod目录下创建一个go.mod的文件,内容如下:

module github.com/benben2015/testmod

这样我们就把testmod包变成了module,现在我们将代码push到远程仓库,这样其他人就可以使用go get命令来使用它了。

git push -u origin master

别人如何使用module

Go modules的版本控制遵循语义化版本,划重点 尤其是Go会使用仓库的标签来查找版本。例如:版本2应该和版本1,版本0有很大不同。默认情况下,Gofetch仓库中最新的带有标签的可用版本。

Module的版本控制

使用git tag命令来发布我们的1.0.0版本。

git tag v1.0.0
git push --tags

上面的命令将会在仓库中的当前代码上创建tag,作为我们的版本1.0.0。虽然Go没有强制创建个新分支来发布主版本的一些修复版本,但是建议这样。

git checkout -b v1
git push -u origin v1

使用module

现在我们可以使用我们之前创建的module,新建一个工程,然后创建main.go文件。

package main

import (
    "fmt"

    "github.com/benben2015/testmod"
)

func main() {
    fmt.Println(testmod.SayHello("China"))
}

在没有module功能之前,我们可能使用上面的包时,需要通过go get github.com/benben2015/testmod命令先下载包。但是使用modules,就没那么麻烦。

首先我们需要在程序中使modules功能可用,然后使用命令go mod init mod。执行完毕后,将会创建一个新的文件go.mod,内容为:

module mod

现在执行构建命令,你将会发现Go命令会自动的拉取程序中导入的包。

go build

go: finding github.com/benben2015/testmod v1.0.0
go: downloading github.com/benben2015/testmod v1.0.0

这时我们再检查go.mod文件,你将会看到变化:

module mod
require github.com/benben2015/testmod v1.0.0

同时,你也可以看到一个新的文件go.sum,里面包含依赖包的hash值来确保正确的版本和文件。

github.com/benben2015/testmod v1.0.0 h1:kiEBYKHX5VR04NwYHo4QTZfd5F6nkeCpvDi5tr5UuBo=
github.com/benben2015/testmod v1.0.0/go.mod h1:nJ45ppreUJfCWss5GtOwRC5FVfGv0p0ii1rrh7Sqdi0=

制作bug修复版本

如果版本有小的改动,一般主版本号不用变,只是次版本改变。例如我们之前创建的testmod模块变成这样

func SayHello(name string) string {
    return fmt.Sprintf("Hi, %s!", name)
}

然后重新建立标签,并push到远程仓库。

git tag v1.0.1
git push --tags origin master

更新使用的modules

默认情况下,Go不会主动的去更新modules。所以需要我们告诉Go去更新,使用命令go get

  • 运行go get -u,将会使用依赖包的最新版本。例如更新1.0.0到1.0.1或者1.1.0。
  • 运行go get -u=patch将会更新依赖包的版本到最新的修订版本。例如更新1.0.0到1.0.1。
  • 运行go get package@version将会更新依赖包的版本到特定版本。

因此,当执行go get -u后,我们的go.mod文件将会变成

module mod
require github.com/benben2015/testmod v1.0.1

制作主版本

当版本有大的更新,主版本号要变。Go modules认为主版本号不同的modules是完全不同的包。例如我们将testmod包中的文件做如下变化:

package testmod

import (
    "errors"
    "fmt"
)

// SayHello returns a friendly greeting in language lang
func SayHello(name, lang string) (string, error) {
 	switch lang {
 	case "en":
 		return fmt.Sprintf("Hi, %s!", name), nil
 	case "pt":
 		return fmt.Sprintf("Oi, %s!", name), nil
 	case "es":
 		return fmt.Sprintf("¡Hola, %s!", name), nil
 	case "fr":
 		return fmt.Sprintf("Bonjour, %s!", name), nil
 	default:
 		return "", errors.New("unknown language")
 	}
}

版本2更改导入路径,通过在go.mod文件中追加新的版本路径module github.com/benben2015/testmod/v2。然后和之前一样,添加标签并push

git tag v2.0.0
git push --tags origin v2

更新主版本

前面已经提到过,使用go get -u不会将版本v1.0.1更新到2.0.0。那么应该怎么做呢。首先将程序修改成这样:

package main

import (
    "fmt"
    "github.com/benben2015/testmod/v2"
)

func main() {
    g, err := testmod.SayHello("China", "pt")
    if err != nil {
        panic(err)
    }
    fmt.Println(g)
}

然后使用go build命令进行构建,Go将会拉取2.0.0的版本。注意: 尽管我们的导入路径后面有v2,但是Go在使用模块时还是会使用testmod

正如之前提到的,主版本号不同,Go认为是不同的包,所以你可以在相同的文件里引用不兼容的版本。

package main

import (
    "fmt"
    "github.com/benben2015/testmod"
    testmodML "github.com/benben2015/testmod/v2"
)

func main() {
    fmt.Println(testmod.SayHello("China"))
    g, err := testmodML.SayHello("China", "pt")
    if err != nil {
        panic(err)
    }
    fmt.Println(g)
}

参考文章

  1. Introduction to Go Modules

你可能感兴趣的:(GO学习总结)