go语言中,从1.11开始,引入module,进行版本管理。

通过使用module,工程目录的位置不用必须放在GOPATH下。

本文介绍 module的使用。

下文中用的Go版本是1.13。

1. go mod命令

通过go mod可以进行modules的相关操作。

首先看下 go mod命令:

$ go help mod
Go mod provides access to operations on modules. Note that support for modules is built into all the go commands,
not just 'go mod'. For example, day-to-day adding, removing, upgrading,
and downgrading of dependencies should be done using 'go get'.
See 'go help modules' for an overview of module functionality. Usage: go mod <command> [arguments] The commands are: download download modules to local cache // 下载依赖的module到本地cache
edit edit go.mod from tools or scripts
graph print module requirement graph
init initialize new module in current directory // 在当前目录下初始化新的module
tidy add missing and remove unused modules // 添加缺失的module,移出不用的module
vendor make vendored copy of dependencies // 将依赖复制到vendor下
verify verify dependencies have expected content
why explain why packages or modules are needed Use "go help mod <command>" for more information about a command.

2.使用module举例

2.1 定义module

在任意目录下创建工程目录,可以不是GOPATH路径下。

$ mkdir hello_mysql
$ pwd
/home/lanyang/workspace/go_example/hello_mysql $ go mod init hello_mysql
go: creating new go.mod: module hello_mysql $ ll
-rw-rw-r--. 1 lanyang lanyang 28 Dec 21 18:25 go.mod $ cat go.mod
module hello_mysql go 1.13

新建源码文件 main.go, 内容如下:

// main.go

package main

import (
"database/sql"
"log" _ "github.com/go-sql-driver/mysql" ) var DB *sql.DB
var dataBase = "root:Aa123456@tcp(192.168.0.101:3306)/?timeout=5s&readTimeout=6s" func mysqlInit() {
var err error
DB, err = sql.Open("mysql", dataBase)
if err != nil {
log.Fatalln("open db fail:", err)
} } func main() {
mysqlInit() execSql()
} func execSql() {
var value int
err := DB.QueryRow("select 1").Scan(&value)
if err != nil {
log.Println("query failed:", err)
return
} log.Println("value:", value)
}

以上代码实现连接MySQL服务器,执行简单的SQL语句。

2.2 编译

$ go build
go: downloading github.com/go-sql-driver/mysql v1.4.1
go: extracting github.com/go-sql-driver/mysql v1.4.1
go: finding github.com/go-sql-driver/mysql v1.4.1 $ ll
total 5788
-rw-rw-r--. 1 lanyang lanyang 75 Dec 22 16:57 go.mod
-rw-rw-r--. 1 lanyang lanyang 179 Dec 22 16:57 go.sum
-rwxrwxr-x. 1 lanyang lanyang 5912033 Dec 22 16:58 hello_mysql
-rw-rw-r--. 1 lanyang lanyang 669 Dec 22 16:57 main.go

在Go 1.13中,继续使用临时环境变量GO111MODULE来设置是否使用module。

GO111MODULE 可设置为off, on, 或auto (默认)。

如果 GO111MODULE=auto 或没有设置, go command(即go build, go test go get等)是否使用module取决于是否存在go.mod文件。

如果当前目录,或父目录中存在go.mod文件,那么go command就会使用module,否则不会使用module。

例子中,没有设置GO111MODULE,保持默认值。

通过定义module,已经创建了go.mod文件,这样,执行go command的时候,就会使用module 查找和下载依赖包,并将依赖包信息添加到go.mod文件中。

下载的依赖包放在$GOPATH/pkg/mod

$ ll $GOPATH/pkg/mod/
total 8
drwxrwxr-x. 3 lanyang lanyang 4096 Dec 22 16:58 cache
drwxrwxr-x. 3 lanyang lanyang 4096 Dec 22 16:58 github.com

go.mod文件内容被修改为:

module hello_mysql

go 1.13

require github.com/go-sql-driver/mysql v1.4.1

编译后,创建可执行文件hello_mysql,执行:

$ ./hello_mysql
2019/12/22 17:19:19 value: 1

3.module 与 vendor

为了兼容老版本,或者想把所有的依赖包放在一个目录下,可以使用go mod vendor

go mod vendor会在根目录下创建 vendor目录,里面存放所有的依赖包。

编译的时候,加上选项-mod=vendor,就可以使用vendor目录下的依赖包。

继续使用上面的例子。

清理pkg/mod:

$ rm -rf $GOPATH/pkd/mod

例子代码目录下,只保留go.modmain.go

使用vendor存放依赖包,执行go mod vendor:

$ go mod vendor
go: downloading github.com/go-sql-driver/mysql v1.4.1
go: extracting github.com/go-sql-driver/mysql v1.4.1
go: finding google.golang.org/appengine v1.6.5
go: downloading google.golang.org/appengine v1.6.5
go: extracting google.golang.org/appengine v1.6.5 $ ll
total 16
-rw-rw-r--. 1 lanyang lanyang 128 Dec 22 17:23 go.mod
-rw-rw-r--. 1 lanyang lanyang 1034 Dec 22 17:23 go.sum
-rw-rw-r--. 1 lanyang lanyang 669 Dec 22 17:19 main.go
drwxrwxr-x. 4 lanyang lanyang 4096 Dec 22 17:23 vendor

vendor目录以及go.sum文件被创建。

查看go.mod文件,内容被修改为:

module hello_mysql

go 1.13

require (
github.com/go-sql-driver/mysql v1.4.1
google.golang.org/appengine v1.6.5 // indirect
)

查看下vendor目录的内容:

$ ll vendor/
total 12
drwxrwxr-x. 3 lanyang lanyang 4096 Dec 22 17:23 github.com
drwxrwxr-x. 3 lanyang lanyang 4096 Dec 22 17:23 google.golang.org
-rw-rw-r--. 1 lanyang lanyang 145 Dec 22 17:23 modules.txt

可以看到目录下存放着所有的依赖包。

编译时,添加-mod=vendor

$ go build -mod=vendor
$ ll
total 5792
-rw-rw-r--. 1 lanyang lanyang 128 Dec 22 17:23 go.mod
-rw-rw-r--. 1 lanyang lanyang 1034 Dec 22 17:23 go.sum
-rwxrwxr-x. 1 lanyang lanyang 5912033 Dec 22 17:34 hello_mysql
-rw-rw-r--. 1 lanyang lanyang 669 Dec 22 17:19 main.go
drwxrwxr-x. 4 lanyang lanyang 4096 Dec 22 17:23 vendor

此时,就会在vendor中查找依赖包。

执行:

$ ./hello_mysql
2019/12/22 17:36:40 value: 1

这种方式中,既使用了module特性,摆脱了工程目录对GOPATH的依赖,又使用了vendor存放依赖包。

尤其是在上线前的编译和打包阶段,提前在vendor目录存放依赖包,就可以不用再通过网络去下载,避免了网络不稳定的影响,从而可以节省大量的时间。

4.参考

关于go module

go mod 使用

Go Module 入门使用

go module 使用举例的更多相关文章

  1. npm手册

    npm现在都是随同NodeJS一起安装的包管理和分发工具,所以npm的安装,只要下载新版的nodejs已经集成了npm. 安装好了以后,直接输入npm或者npm help,会出来一些npm自带的命令. ...

  2. grunt使用一步一步讲解

    grunt 是一套前端自动化工具,一个基于nodeJs的命令行工具,一般用于:① 压缩文件② 合并文件③ 简单语法检查 对于其他用法,我还不太清楚,我们这里简单介绍下grunt的压缩.合并文件,初学, ...

  3. 【盗墓笔记】图解使用fat-aar方式在AndroidStudio中打包嵌套第三方aar的aar

    将一些项目中的一些独立功能打包成aar,不仅能于项目解耦,还能够提供给其它项目使用相同的功能,可谓是为项目开发带来了很大的便利.最近第一次做sdk,碰到一些问题,花了不少时间才解决,所以这里做一下简单 ...

  4. angular源码阅读,依赖注入的原理:injector,provider,module之间的关系。

    最开始使用angular的时候,总是觉得它的依赖注入方式非常神奇. 如果你跳槽的时候对新公司说,我曾经使用过angular,那他们肯定会问你angular的依赖注入原理是什么? 这篇博客其实是angu ...

  5. module.export和export

    module.exports 和 exports 是引用到的同一个对象,类似下面代码所示(为了举例,不是完全的正确): var module.exports = {};        var expo ...

  6. 一步一步学Python(1) 基本逻辑控制举例和编码风格规范

    (1) 基本逻辑控制举例和编码风格规范 1.while死循环 2.for循环 3.if,elif,else分支判断 4.编码风格(官方建议) 版本:Python3.4 1.while死循环 #func ...

  7. python yield用法举例说明

    1  yield基本用法 典型的例子: 斐波那契(Fibonacci)數列是一个非常简单的递归数列,除第一个和第二个数外,任意一个数都可由前两个数相加得到.1 2 3 5 8…… def fab(ma ...

  8. Linux下c函数dlopen实现加载动态库so文件代码举例

    dlopen()是一个强大的库函数.该函数将打开一个新库,并把它装入内存.该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的.这种机制使得在系统中添加或者删除一个模块时,都不需要重新编译了. ...

  9. linux driver module

    本文将对Linux系统中的sysfs进行简单的分析,要分析sysfs就必须分析内核的driver-model(驱动模型),两者是紧密联系的.在分析过程中,本文将以platform总线和spi主控制器的 ...

随机推荐

  1. 使用私有api统计ios app运行时间及次数

    利用<iphone SprintBoard部分私有API总结>中提到的私有API,可以做很多越狱以前实现不了的事情. 比如,利用一个后台运行的app,监控该iphone上所有app的运行次 ...

  2. Redis和MemCache静态Map做缓存区别

    本地缓存和分布式缓存 本地缓存:使用自带的map或者guava实现的是本地缓存,最主要的特点是轻量以及快速,生命周期随着jvm的销毁而结束,并且在多实例的情况下,每个实例都需要各自保存一份缓存,缓存不 ...

  3. pymysql_mysql密码重置方法,连接局域网数据库的解决办法

    https://blog.csdn.net/qq_37176126/article/details/72824106   pymysql模块的操作 https://blog.csdn.net/skh2 ...

  4. 《浏览器工作原理与实践》<03>HTTP请求流程:为什么很多站点第二次打开速度会很快?

    一个 TCP 连接过程包括了建立连接.传输数据和断开连接三个阶段. 而 HTTP 协议,正是建立在 TCP 连接基础之上的.HTTP 是一种允许浏览器向服务器获取资源的协议,是 Web 的基础,通常由 ...

  5. 05_Hive分区总结

    2.1.创建分区表并将本地文件的数据加载到分区表: 使用下面的命令来创建一个带分区的表 通过partitioned by(country string)关键字声明该表是分区表,且分区字段不能为crea ...

  6. VS---《在VS2010中 使用C++创建和使用DLL》(001)

    VS---<在VS2010中 使用C++创建和使用DLL>(001) 需要学习制作和使用动态库,现在知道:DLL调用有两种方式,一种是静态调用,另外一种是动态调用.详细的还不算明白,等后期 ...

  7. 一图一知-TS之函数function

  8. Almost Acyclic Graph CodeForces - 915D (思维+拓扑排序判环)

    Almost Acyclic Graph CodeForces - 915D time limit per test 1 second memory limit per test 256 megaby ...

  9. Educational Codeforces Round 37 (Rated for Div. 2)C. Swap Adjacent Elements (思维,前缀和)

    Educational Codeforces Round 37 (Rated for Div. 2)C. Swap Adjacent Elements time limit per test 1 se ...

  10. MFC 用户登录、注册、工作主窗体

    创建项目由向导生成的窗体作为工作的主窗体.用户登录.注册窗体添加对话框来实现. [具体功能] 1.主窗体应该出现在登录窗体成功之后. 2.登录窗体关闭(右上角❌),程序直接退出. 在App.cpp的I ...