go 1.11
开始可以使用更优雅灵活的module
机制做包依赖管理,能直接感受到的优点如下:
- 项目路径可以脱离
$GOPATH
了,不需要必须放在$GOPATH/src
下。 - 项目内部模块的引入是基于
moduleName
而不再死板的基于projectName
了。 - 半自动维护依赖,如果你很懒,你甚至可以不需要使用
get
预先安装依赖,module
在run test build
时会检测未下载的依赖,并自动下载它们。
回想以前吧!$GOPATH/src/projectName
后,项目中各模块互相引用的话都是基于projectName
(go 的包加载机制导致的,去 $GOROOT/src
和 $GOPATH/src
去寻址,所以projectName
也需要作为包引入路径的一部分),别人使用你的项目时也必须是projectName
,否则就得把项目内的所有projectName
改为他们的项目名,不优雅极了。
而module
模式下,项目的包域是moduleName
,和projectName
无关,项目名称怎样都好,moduleName
会注册到加载路径中去。
虽然
module
可以灵活到消除
项目名
作为项目模块引入路径的槽点,但如果后面要转为普通的
vendor
模式的话,我们还是建议
moduleName
同
projetName
保持一致。
GO111MODULE
首先要知道,mod
模式下安装的依赖包都存放在$GOPATH/pkg/mod
目录下,在 mod
模式下导入第三方包时会去$GOPATH/pkg/mod
目录下加载,而不是普通模式下的$GOPATH/src
| project/vendor
目录。
mod
模式是否开启由环境变量GO111MODULE
决定,GO111MODULE
环境变量有三个值:on
,auto(默认值)
,off
。
on
:强制开启mod
模式,此模式下不会去 $GOPATH/src
,project/vendor
下加载第三方依赖包,只会去$GOPATH/pkg/mod
下载加载。auto
:如果项目在 $GOPATH/src
下,则转为普通模式,否则,转为mod
模式。off
:关闭mod
模式,转为普通的$GOPATH/src
,project/vendor
模式。
init
初始化项目为module
模式:go mod init moduleName
# 不需要必须在 $GOPATH/src 下
mkdir go_mod_proj && cd go_mod_proj
go mod init app
# go: creating new go.mod: module app
# 会生成一个 go.mod 文件 查看内容如下
vi go.mod
module app
go 1.12
# module app 即定义了当前项目的包域
# 往常我们要引入 go_mod_proj 下的 test 包需要
# import "go_mod_proj/test"
# module 模式下则是 优雅的很 像 PHP 的命名空间映射一样灵活
# import "app/test"
示例
tree .
.
├── go.mod
├── main.go
└── utils
└── msg.go
# go.mod
module app
go 1.12
# utils/msg.go
package utils
func Hello() {
println("hello go")
}
# main.go
package main
import (
"app/utils" // 注意项目模块包的引入是以 moduleName 作为包域的
)
func main() {
utils.Hello()
}
# go run main.go
自动维护
我们日常开发时需要某依赖包的话,都会使用 go get
下载后再运行,module
模式下因为会自动的解析项目依赖,会自动的去下载那些未在本地的依赖包,删除那些不再需要的依赖包。
比如我们引入一个 github.com/sqrtcat/easy_go
到项目代码里,并调用 easy_go.Hello()
方法。
package main
import (
"github.com/sqrtcat/easy_go"
)
func main() {
easy_go.Hello()
}
# 直接运行不会报错
go run main.go
我们可以直接运行而不会报错(非gomod
会报错),gomod
会自动的检测未下载的包,自动下载,解决依赖问题。
tidy
tidy
主要用来手动维护项目的包依赖,会检测项目当前的依赖,做相应的依赖添加或移除。
相当于composer
的 install
, govendor
的sync
。
# 比如引入一个依赖包
package main
import (
"app/utils"
"github.com/sqrtcat/easy_go"
)
func main() {
utils.Hello()
easy_go.Hello()
}
运行一下tidy
[root@localhost go_mod_proj]# go mod tidy
go: finding github.com/sqrtcat/easy_go latest
go: downloading github.com/sqrtcat/easy_go v0.0.0-20190717091231-f38efee9a600
go: extracting github.com/sqrtcat/easy_go v0.0.0-20190717091231-f38efee9a600
可以看到 tidy
自动为我们下载了未安装的依赖包
# 查看 go.mod
module app
go 1.12
require github.com/sqrtcat/easy_go v0.0.0-20190717091231-f38efee9a600
删掉 main.go
中 easy_go
包
# main.go
package main
import (
"app/utils"
)
func main() {
utils.Hello()
}
运行一下
go mod tidy
# 查看 go.mod
module app
go 1.12
可以看到已经没有 github.com/sqrtcat/easy_go
依赖了。
当我们下载了别人的mod
项目到本地时,可以直接run
,mod
会自动下载未安装的依赖,也可以执行一次tidy
手动维护一次依赖,当我们要上传自己本地的项目到仓库时,应该先执行以下tidy
命令,清理一下无用的依赖,再上传。
edit
不常用,忽略
vendor
将module
项目转为普通的vendor
项目,这时就需要将项目移至$GOPATH/src
下,并要保证projectName
同moduleName
保持一致,否则要手动去修改项目模块包的加载路径了。