10分钟学会go module

作者: 小新

发布于 2020-01-06 | 最后更新 2020-01-06


前两天参加了 GopherChina 的大会收获颇多,go module算一个,下面把总结使用分享给大家,有问题的话希望指正。

基本使用

环境准备 golang 1.11的朋友,开启 GO11MODULE=on ,并且确保实验目录不在 GOPATH 中

golang 1.12的朋友,确保实验目录不在 GOPATH 中。

初始化go module环境 带git的项目

直接从github上面clone一个项目下来。

直接执行 go mod init 会自动生成带git地址的packagename

gomodtest_base git:(master) ✗ go mod init
go: creating new go.mod: module github.com/e421083458/gomodtest_base

不带git的项目

直接执行

go mod init packagename

下载依赖包 只下载依赖包

go mod download
➜  new_module_test go mod download
go: finding github.com/e421083458/gomodtest_dep v0.0.0-20190501153957-6ff7f41fdb83
go: finding github.com/e421083458/gomodtest_base v1.0.1
go: finding github.com/e421083458/gomodtest_base/v2 v2.0.0
go: finding github.com/jianfengye/collection v0.0.0-20190426092112-28c4a03f0c86
go: finding github.com/pkg/errors v0.8.1

拉取必须模块,移除不用的模块

go mod tidy复制代码

注意点:

如果tag对应内容有更新,需要删除pkg中的缓存内容。这点比较恶心了。

cd $GOPATH/pkg/mod
rm -rf *
go get、 go run、go build 也会自动下载依赖

添加新依赖包 方法一: 直接修改 go.mod 文件,然后执行 go mod download 方法二: 使用 go get packagename@v1.2.3,会自动更新 go.mod 文件的 方法三: go run、go build 也会自动下载依赖

将依赖包下载到vendor目录 go mod vendor 注意: 这里只会下载对应版本的包文件,不会把所有版本下载。跟之前1.11使用方式一致。

亮点功能一:使用replace本地包替换 有时候国外软件可能被墙,这个功能就能派上用场了。 main.go

package main
import "my/example/pkg"
func main() {
    pkg.Hello()
}

go.mod

module my-mod

require my/example/pkg v0.0.0
replace my/example/pkg => ./pkg

注意点: 顶层依赖可替换但间接依赖不可替换

亮点功能二:语意化版本 semver—Semantic Versioning semver是官方为了类库升级引入的新规范,即: “If an old package and a new package have the same import path, the new package must be backwards compatible with the old package.” - go modules wiki “ 如果旧软件包和新软件包具有相同的导入路径,则新软件包必须向后兼容旧软件包。”

main.go

package main
import (
    "fmt"
    v1 "github.com/e421083458/gomodtest_base"
    v2 "github.com/e421083458/gomodtest_base/v2"
)
func main(){
    v2.NewIntCollection("hello","sex")
    v1.NewIntCollection("hello")
    fmt.Println("hello");
}

go.mod

module new_module_test

require (
    github.com/e421083458/gomodtest_base v1.0.1
    github.com/e421083458/gomodtest_base/v2 v2.0.0
)

亮点功能三:依赖包冲突问题 情况1:直接 引用的包 和 间接引用的包是同一个包,但版本不同时? 依赖关系: gomodtest_test|–> gomodtest_dep |–> gomodtest_base@v1.0.0 |–> gomodtest_base@v1.0.1
go mod tidy 时,gomodtest_test会自动更新到与依赖包关联的第三方包相同版本号,并写入到go.mod,从而解决了版本冲突问题。

情况2: 间接引用的两个包是同一个包,但版本不同时? 比如以下场景: gomodtest_test|–> gomodtest_dep |–> gomodtest_base@v1.0.0 |–> gomodtest_dep2 |–> gomodtest_base@v1.0.1 go mod tidy 时,默认使用第一个包引用版本号,gomodtest_base@v1.0.1,并写入到go.mod,这个时候就要注意两个版本是否功能完全兼容的问题了。

亮点功能四:自动查找包依赖 go mod 遵循了之前go get 自动下载依赖特性。所有的依赖包会自动全部下载。 未启用 go mod 功能的包会自动下载最高 tag 版本或最高 master commit版本 我之前也以为go mod只会自动查询使用了go mod的功能的包。

new_module_test go mod download
go: finding github.com/e421083458/gomodtest_dep v0.0.0-20190501153957-6ff7f41fdb83
go: finding github.com/e421083458/gomodtest_base v1.0.1
go: finding github.com/e421083458/gomodtest_base/v2 v2.0.0
go: finding github.com/jianfengye/collection v0.0.0-20190426092112-28c4a03f0c86
go: finding github.com/pkg/errors v0.8.1

总结: 大部分场景下 go mod init 和 go mod tidy 两个命令就够用了

查看$GOPATH/pkg/mod里面的文件就知道了,mod做了一件类似maven的事把所有包都打上了版本号。 可以说这是 golang 迈向高大上语言的标志。 从此我们不再为多版本使用的困扰,也不再为IDE打开一个新项目后等待n分钟的生成缓存犯愁。推荐大家丢掉vendor使用统一管理。

semver 将版本信息绑定进包名对于习惯了传统包管理器方案的用户来说显得有些怪异,可能需要花上一些额外时间适应。

文档引用: https://www.cnblogs.com/apocelipes/archive/2019/01/20/10295096.html https://github.com/golang/go/wiki/Modules#semantic-import-versioning https://www.cnblogs.com/apocelipes/p/9534885.html https://www.cnblogs.com/apocelipes/p/9537659.html