Golang依赖管理工具: go module 详解
Golang依赖管理工具: go module (go1.11+)
大多数语言都会有包管理工具,像Node有npm
,PHP有composer
,Java有Maven
和Gradle
。
可是,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 build
或 go 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 详解的更多相关文章
- redis cluster管理工具redis-trib.rb详解
redis cluster管理工具redis-trib.rb详解 来源 http://weizijun.cn/2016/01/08/redis%20cluster%E7%AE%A1%E7%90%86% ...
- Golang依赖管理工具:glide从入门到精通使用
这是一个创建于 2017-07-22 05:33:09 的文章,其中的信息可能已经有所发展或是发生改变. 介绍 不论是开发Java还是你正在学习的Golang,都会遇到依赖管理问题.Java有牛逼轰轰 ...
- 进程管理工具之supervisor[详解]
原文链接:https://blog.csdn.net/weixin_42390791/article/details/88866237 一.问题背景1.背景 如何才能让一个进程摆脱终端,获得相对 ...
- golang多个项目时如何配置GOPATH,使用gb包依赖管理工具,不同项目配置不同的GOPATH的
golang多个项目时如何配置GOPATH,使用gb包依赖管理工具,不同项目配置不同的GOPATH的 1:执行脚本setGoPath.sh#!/bin/bashif [[ $GOPATH =~ .*$ ...
- 黑苹果引导工具 Clover 配置详解及Clover Configurator使用
黑苹果引导工具 Clover 配置详解及Clover Configurator使用 2017-03-11 14:01:40 by SemiconductorKING 转自:@三个表哥 简介: 可 ...
- Go依赖管理及Go module使用
Go语言的依赖管理随着版本的更迭正逐渐完善起来. 依赖管理 为什么需要依赖管理 最早的时候,Go所依赖的所有的第三方库都放在GOPATH这个目录下面.这就导致了同一个库只能保存一个版本的代码.如果不同 ...
- golang包管理工具
软件开发中,不可避免的会使用到第三方库,因此包管理工具可以极大的方便开发者管理第三方依赖,避免掉入"依赖地狱". 作为google强大背书的golang语言,golang官方包管理 ...
- 日志分析工具ELK配置详解
日志分析工具ELK配置详解 一.ELK介绍 1.1 elasticsearch 1.1.1 elasticsearch介绍 ElasticSearch是一个基于Lucene的搜索服务器.它提供了一个分 ...
- KVM镜像管理利器-guestfish使用详解
原文 http://xiaoli110.blog.51cto.com/1724/1568307 KVM镜像管理利器-guestfish使用详解 本文介绍以下内容: 1. 虚拟机镜像挂载及w2k8 ...
- Go 包依赖管理工具 —— govendor
govendor 是一个基于 vendor 机制实现的 Go 包依赖管理命令行工具.与原生 vendor 无侵入性融合,也支持从其他依赖管理工具迁移,可以很方便的实现同一个包在不同项目中不同版本.以及 ...
随机推荐
- Codeforces Round #844 (Div. 1 + Div. 2, based on VK Cup 2022 - Elimination Round) A-D
比赛链接 A 题意 设计一条线路要贴着6个墙面走,从 \((a,b)\) 到 \((f,g)\) ,线路长度最短. 题解 知识点:模拟. 分类取最短即可. 时间复杂度 \(O(1)\) 空间复杂度 \ ...
- Hugging Face 开源库介绍
Hugging Face 的开源生态今年成长迅速,timm 成为新加入的成员.diffusers.evaluate 以及 skops 等各种库蓬勃发展. Transformers Transforme ...
- 小白从零到AIoT之路(前言)
什么是AIoT 简单来说就是AI(人工智能)+IoT(物联网)= AIoT(人工智能物联网). AIoT融合AI技术和IoT技术,通过物联网产生.收集来自不同维度的.海量的数据存储于云端.边缘端,再通 ...
- 干货满满的 Zookeeper 学习笔记
读完< ZooKeeper : Wait-free coordination for Internet-scale systems > 论文的一些笔记,记录下来,方便以后查看 在读论文的时 ...
- 洛谷p5723
1 #include<bits/stdc++.h> 2 using namespace std; 3 int z(int a) 4 { 5 if(a==2) return 1; 6 if( ...
- evil 控制窗口大小,比快捷键方便
下面是vim原本的支持的键 可以用于 emacs evil ,evil 用这个比用快捷键还方面些 1.纵向调整 :res[ize] num 指定当前窗口为num列num行 :res[ize] +num ...
- JAVA虚拟机02---JAVA虚拟机运行时数据区域简介
JAVA虚拟机运行时数据区域 1.程序计数器 1)它可以看做是当前线程执行的字节代码的行指示器,通过改变计数器的值来决定下一步执行的代码 2)它是线程私有的,每个线程都有自己的程序计数器(JAVA ...
- 【LeetCode字符串#06】KMP巩固练习:重复子串
重复的子字符串 力扣题目链接(opens new window) 给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成.给定的字符串只含有小写英文字母,并且长度不超过10000. 示例 1: ...
- Idea的jdbc中的查询与增删该
在上一篇的折磨中 终于写好了代码 来总结一下其中的奥妙 (相同部分:)1.有mysql并且与主机建立连接 2.有jar包并且复制到自己创建的libs文件下,右键add 3.需要写main方法 4.需要 ...
- MySQL数据库报1055错误
有点坑啊,当初装MySQL数据库的时候没有整配置文件,结果MySQL报1055错误的时候,网上的解决办法都说如果需要永久生效的话,只能通过改配置文件实现,but,我没有配置文件,蜜汁尴尬啊 1.已安装 ...