Golang依赖管理工具: go module (go1.11+)

大多数语言都会有包管理工具,像Node有npm,PHP有composer,Java有MavenGradle

可是,Go语言一直缺乏一个官方的包管理(之前有个Dep被称为官方试验品official experiment)。

终于,在2018年发布的go1.11 版本中,新增了go module管理模块功能,用来管理依赖包。

要知道,在这个之前,想要对go语言包进行管理,只能依赖第三方库实现,比如Vendor,GoVendor,GoDep,Dep,Glide等等,对于初学者来说,真的是选择困难症。

关于Workspaces和GOPATH

go1.11 之前,如果不使用第三方包管理工具可行,就是直接使用go get安装第三方包。

工作空间Workspaces,是Go项目的根目录,也就是 GOPATH是GO项目必备的环境变量,用来存放Go的开发代码和第三方包代码,代码需要按照一定的目录安排。

指定GOPATH路径:

$ echo $HOME
/Users/wangtom $ export GOPATH=$HOME/go

查看GOPATH:

$ go env |grep GOPATH
GOPATH="/Users/wangtom/go"

开启 GO111MODULE:

要使用 go module, 需要先设置 GO111MODULE 环境变量,即设置GO111MODULE=on。如果没设置,执行命令的时候会有提示。

# 使用 go 命令设置
$ go env -w GO111MODULE=on # linux / mac
$ export GO111MODULE=on $ go env |grep GO111MODULE
GO111MODULE="on"

从 Go1.13 版本开始,go module 成为了Go语言默认的依赖管理工具,不需要再手动设置 GO111MODULE=on 了。

这是因为,默认设置的GO111MODULE=auto, 导致 modules 默认在 GOPATH/src 路径下是不启用的。

如果需要在 GOPATH/src 也能使用modules, 需要把 GO111MODULE 环境变量设置为 on.

$ export GO111MODULE=on
$ go mod init github.com/cnwyt/mylib
go: creating new go.mod: module github.com/cnwyt/mylib

创建一个公用模块 mylib 模块

创建一个公共模块mylib:

模块命名为 github.com/cnwyt/mylib,就是我们创建的GitHub仓库的路径,方便我们以后提交代码、供别人的调用。

(1)按照原来GOPATH开发模式,创建新的包需要放置在 $GOPATH/src/github.com

创建一个目录mylib目录,并进入该命令:

$ mkdir -p $GOPATH/src/github.com/cnwyt/mylib
$ cd $GOPATH/src/github.com/cnwyt/mylib

(2)使用 go mod init 命令初始化:

随便找一个目录,比如在 ~/dev/go-demo:

$ mkdir mylib
$ cd mylib
$ go mod init github.com/cnwyt/mylib
go: creating new go.mod: module github.com/cnwyt/mylib $ ls
go.mod $ cat go.mod
module github.com/cnwyt/mylib
go 1.19

初始化后,会生成一个go.mod文件,类似 npm 里的 package.json 或者 composer 的 composer.json 的一个文件。

创建一个名为util的公共包,公共包我们一般放置放在项目的 pkg 目录下:

# mylib/pkg/util/hello.go
package util import "fmt" func SayHello() {
fmt.Println("nihao -- from mylib")
}

在main函数中调用,

package main

import (
"fmt" // <----- 这里引入本项目的 utl 包
// 路径与使用 go mod init初始化时的 module 名称一致
"github.com/cnwyt/mylib/pkg/util"
) func main() {
fmt.Println("Hello, mylib!") // <----- 这里调用本项目的 utl 包的方法
util.SayHello()
}

常用的go mod命令如下表所示:

命令 作用
go mod init 初始化当前文件夹,创建 go.mod 文件
go mod edit 编辑 go.mod 文件
go mod tidy 增加缺少的包,删除无用的包
go mod download 下载依赖包到本地(默认在 GOPATH/pkg/mod 目录)
go mod graph 打印模块依赖图
go mod vendor 将依赖复制到 vendor 目录下
go mod verify 校验依赖
go list -m all 查看所有的依赖

创建一个本地模块 appdemo , 并调用 mylib:

在 GOPATH 以外的目录里,创建一个 appdemo 的应用目录,作为自己的项目目录。

因为作为应用目录不需要别人调用,不需要放到网上,因此不加 github.com 域名,直接起个 mod 名字即可,这里起的名字是 appdemo,和该项目的目录同名。

$ mkdir appdemo && cd appdemo

$ go mod init appdemo
go: creating new go.mod: module appdemo $ vi main.go

创建一个 main.go 文件:

package main

import "fmt"

func main() {
fmt.Println("Hello, appdemo!");
}

在 appdemo 项目,我们也创建一个名为 util 的公共包(该包仅供该项目里共用),公用包我们一般放置放在项目的 pkg 目录下:

# mylib/pkg/util/hello.go
package util import "fmt" // UnixTime time()
func UnixTime() int64 {
return time.Now().Unix()
}

在 main.go 里调用:

package main

import (
"fmt" // <----- 这里引入本项目的 utl 包
// 路径与使用 go mod init初始化时的 module 名称一致
"pkg/util"
) func main() {
fmt.Println("Hello, mylib!") // <----- 这里调用本项目的 utl 包的方法
t := util.UnixTime()
fmt.Println("timestamp: ", t)
}

调用前边的公用模块 mylib:

初始化该模块,引入github.com/cnwyt/mylib模块,指定版本为latest:

$ go mod init appdemo
$ go mod edit -require github.com/cnwyt/mylib@latest

查看 go.mod 文件。

$ cat go.mod
module appdemo go 1.19 require github.com/cnwyt/mylib v0.0.0

这样直接执行 go build 会报错:

$ go build
# <---- 可能是这个报错:
build appdemo: cannot find module for path github.com/cnwyt/mylib # <---- 可能是这个,找不到这个mylib,报错:
go: errors parsing go.mod:
Confirm the import path was entered correctly.

这是为啥呢?

这是因为我们虽然创建了一个名为 github.com/cnwyt/mylib 公用模块,在GOPATH路径里没有这个模块。go mod 去 Github 去找这个模块找不到(还没推送到远程)。

那该怎么办呢?

有两个解决办法: 第一个办法,很简单,就是直接将cnwyt/mylib模块推送的 GitHub上。但是,如果我要修改cnwyt/mylib里的代码,每次都得先推送到GitHub上,才能生效,实在太麻烦了。

那就直接使用第二个办法, 使用 go replace 临时替代:

可以使用 go mod edit 命令修改。或直接修改 go.mod 文件,新增一行 replace:

module helloworld

require github.com/cnwyt/mylib v0.0.0

replace github.com/cnwyt/mylib => /Users/wangtom/dev/go-example/go-mod-demo/mylib

注意版本号必须填写,格式为 v1.2.3, 可以填v0.0.0.

package main

import (
"appdemo/pkg/util"
"fmt" // <----- 这里引入 公共模块 mylib 的 util 包
// <----- 因为与项目里的util包重名了,所以重命名为 util2
util2 "github.com/cnwyt/mylib/pkg/util"
) func main() {
fmt.Println("hello app demo")
timestamp := util.UnixTime() fmt.Println("timestamp: ", timestamp) // <----- 这里调用 公共模块 mylib
util2.SayHello()
}

然后重新运行,可以看到可以正常调用 mylib 里的方法:

$ go run main.go
hello app demo
timestamp: 1666147320
nihao -- from mylib

调用已存在的第三方模块

这里演示调用第三方模块 Redis 操作库 go-redis/redis。

使用 go get 下载安装 go-redis/redis:

$ go get github.com/go-redis/redis/v8

go: added github.com/cespare/xxhash/v2 v2.1.2
go: added github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f
go: added github.com/go-redis/redis/v8 v8.11.5

运行 go buildgo test 会自动从GitHub下载模块,并会修改 go.mod 文件。

如果下载不下来代码,可以设置goproxy模块代理(七牛云提供)。

# Go 1.13 及以上(推荐)
# 打开你的终端并执行 $ go env -w GO111MODULE=on
$ go env -w GOPROXY=https://goproxy.cn,direct

查看 go.mod 文件变化:

module appdemo

go 1.19

require github.com/cnwyt/mylib v0.0.0

require (
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/go-redis/redis/v8 v8.11.5 // indirect
) replace github.com/cnwyt/mylib => /Users/wangtom/dev/go-example/go-mod-demo/mylib

使用 go mod 下载安装的模块,代码会放到 $GOPATH/pkg/mod/ 目录下:


$ ls $GOPATH/pkg/mod/github.com/go-redis
redis
redis@v6.15.9+incompatible

代码示例:

import (
"context"
"github.com/go-redis/redis/v8"
"fmt"
) var ctx = context.Background() func main() {
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
}) err := rdb.Set(ctx, "key", "value", 0).Err()
if err != nil {
panic(err)
} val, err := rdb.Get(ctx, "key").Result()
if err != nil {
panic(err)
}
fmt.Println("key", val) val2, err := rdb.Get(ctx, "key2").Result()
if err == redis.Nil {
fmt.Println("key2 does not exist")
} else if err != nil {
panic(err)
} else {
fmt.Println("key2", val2)
}
// Output: key value
// key2 does not exist
}

参考链接

https://wang123.net/a/golang-go-mod-intro

END

Golang依赖管理工具: go module 详解的更多相关文章

  1. redis cluster管理工具redis-trib.rb详解

    redis cluster管理工具redis-trib.rb详解 来源 http://weizijun.cn/2016/01/08/redis%20cluster%E7%AE%A1%E7%90%86% ...

  2. Golang依赖管理工具:glide从入门到精通使用

    这是一个创建于 2017-07-22 05:33:09 的文章,其中的信息可能已经有所发展或是发生改变. 介绍 不论是开发Java还是你正在学习的Golang,都会遇到依赖管理问题.Java有牛逼轰轰 ...

  3. 进程管理工具之supervisor[详解]

    原文链接:https://blog.csdn.net/weixin_42390791/article/details/88866237 一.问题背景1.背景​   如何才能让一个进程摆脱终端,获得相对 ...

  4. golang多个项目时如何配置GOPATH,使用gb包依赖管理工具,不同项目配置不同的GOPATH的

    golang多个项目时如何配置GOPATH,使用gb包依赖管理工具,不同项目配置不同的GOPATH的 1:执行脚本setGoPath.sh#!/bin/bashif [[ $GOPATH =~ .*$ ...

  5. 黑苹果引导工具 Clover 配置详解及Clover Configurator使用

    黑苹果引导工具 Clover 配置详解及Clover Configurator使用  2017-03-11 14:01:40 by SemiconductorKING 转自:@三个表哥   简介: 可 ...

  6. Go依赖管理及Go module使用

    Go语言的依赖管理随着版本的更迭正逐渐完善起来. 依赖管理 为什么需要依赖管理 最早的时候,Go所依赖的所有的第三方库都放在GOPATH这个目录下面.这就导致了同一个库只能保存一个版本的代码.如果不同 ...

  7. golang包管理工具

    软件开发中,不可避免的会使用到第三方库,因此包管理工具可以极大的方便开发者管理第三方依赖,避免掉入"依赖地狱". 作为google强大背书的golang语言,golang官方包管理 ...

  8. 日志分析工具ELK配置详解

    日志分析工具ELK配置详解 一.ELK介绍 1.1 elasticsearch 1.1.1 elasticsearch介绍 ElasticSearch是一个基于Lucene的搜索服务器.它提供了一个分 ...

  9. KVM镜像管理利器-guestfish使用详解

    原文  http://xiaoli110.blog.51cto.com/1724/1568307   KVM镜像管理利器-guestfish使用详解 本文介绍以下内容: 1. 虚拟机镜像挂载及w2k8 ...

  10. Go 包依赖管理工具 —— govendor

    govendor 是一个基于 vendor 机制实现的 Go 包依赖管理命令行工具.与原生 vendor 无侵入性融合,也支持从其他依赖管理工具迁移,可以很方便的实现同一个包在不同项目中不同版本.以及 ...

随机推荐

  1. 基于WebSocket的实时消息传递设计

    目录 概述 整体架构 设计 流程设计 程序设计 WebSocketServer 概述 新增pom 新增配置类 创建websocket端点 WebSocketClient 概述 安装WebSocketS ...

  2. 序列化框架-Kyro简述

    网上有很多资料说 Kryo 只能在 Java 上使用,这点是不对的,事实上除 Java 外,Scala 和 Kotlin 这些基于 JVM 的语言同样可以使用 Kryo 实现序列化. 1.使用方法 ( ...

  3. vue-echarts数据可视化实现自适应屏幕进行缩放,这个我写了两篇文章,一个用了vue-echarts,一个直接用的charts ,我可真机智 啊~~~

    使用这个后可以实现屏幕自适应 效果如下 <template> <div style="width:100%;height:20rem" ref="res ...

  4. 命令行部署repmgr管理集群+switchover+切换测试

    本次部署未使用securecmd/kbha工具.无需普通用户到root用户的互信. 建立系统数据库安装用户组及用户,在所有的节点执行 root用户登陆服务器,创建用户组及用户并且设置密码 [root@ ...

  5. Vue过滤案例、按键修饰符、数据双向绑定

    目录 Vue过滤案例.按键修饰符.数据双向绑定 一.v-for能循环的类型 二.js的几种循环方式 三.key值的解释 四.数组.对象的检测与更新 五.input的几个事件 六.事件修饰符 七.按键修 ...

  6. 懂九转大肠的微软New Bing 内测申请教程

    最近微软的New Bing开放内测了,网上已经有拿到内测资格的大佬们对比了ChatGPT和New Bing.对比结果是New Bing比ChatGPT更强大.来看看具体对比例子吧 1.时效性更强 Ch ...

  7. Rpc-实现Zookeeper注册中心

    1.前言 本文章是笔主在声哥的手写RPC框架的学习下,对注册中心的一个拓展.因为声哥某些部分没有保留拓展性,所以本文章的项目与声哥的工程有部分区别,核心内容在Curator的注册发现与注销,思想看准即 ...

  8. 冰河指南AI技术社区基于ChatGPT正式启动运营

    大家好,我是冰河~~ 最近ChatGPT真的太火了,科技圈几乎都在争相报导这个黑科技,它能够通过学习和理解人们的语言来和人类进行对话,能够与人们进行交流,甚至可以对你提出的问题进行分析,尽可能给出你想 ...

  9. The Missing Semester - 第二讲 学习笔记

    第二讲 Shell 工具和脚本 课程视频地址: https://www.bilibili.com/video/BV1Vv411v7FR 本机学习使用平台:虚拟机ubuntu18.04.6 主题一:Sh ...

  10. 微信小程序组件封装传值以及问题点规避

    封装组件 1.在components文件加下新建组件文件夹,在该文件夹下新建组件 2.在app.json中注册该组件 "usingComponents": { "page ...