Go后端开发 -- Go Modules

Go后端开发 – Go Modules

文章目录

  • Go后端开发 -- Go Modules
  • 一、什么是Go Modules?
  • 二、GOPATH的工作模式
    • 1.GOPATH模式
    • 2.GOPATH模式的弊端
  • 三、Go Modules模式创建项目
    • 1.go mod命令
    • 2.go mod环境变量
    • 3.使用Go Modules初始化项目
    • 4.修改模块的版本依赖关系
  • 四、Go Modules下import导本地包
    • 1.所有包在同一项目目录下
    • 2.import导入的包与main包不在同一个路径下
    • 3.import导入本地包的格式


一、什么是Go Modules?

Go modules 是 Go 语言的依赖解决方案,发布于 Go1.11,成长于 Go1.12,丰富于 Go1.13,正式于 Go1.14 推荐在生产上使用。
Go moudles 目前集成在 Go 的工具链中,只要安装了 Go,自然而然也就可以使用 Go moudles 了,而 Go modules 的出现也解决了在 Go1.11 前的几个常见争议问题:

  1. Go 语言长久以来的依赖管理问题。
  2. “淘汰”现有的 GOPATH 的使用模式。
  3. 统一社区中的其它的依赖管理工具(提供迁移功能)。

二、GOPATH的工作模式

1.GOPATH模式

Go Modoules的目的之一就是淘汰GOPATH, 那么GOPATH是个什么?
我们输入go env命令行后可以查看到 GOPATH 变量的结果,我们进入到该目录下进行查看,如下:
在这里插入图片描述
在这里插入图片描述
GOPATH目录下一共包含了三个子目录,分别是:

  • bin:存储所编译生成的二进制文件。
  • pkg:存储预编译的目标文件,以加快程序的后续编译速度。
  • src:存储所有.go文件或源代码。在编写 Go 应用程序,程序包和库时,一般会以$GOPATH/src/github.com/foo/bar的路径进行存放。

因此在使用 GOPATH 模式下,我们需要将应用代码存放在固定的$GOPATH/src目录下,并且如果执行go get来拉取外部依赖会自动下载并安装到$GOPATH目录下。

2.GOPATH模式的弊端

在 GOPATH 的 $GOPATH/src 下进行 .go 文件或源代码的存储,我们可以称其为 GOPATH 的模式,这个模式拥有一些弊端.

  1. 无版本控制概念. 在执行go get的时候,你无法传达任何的版本信息的期望,也就是说你也无法知道自己当前更新的是哪一个版本,也无法通过指定来拉取自己所期望的具体版本。
  2. 无法同步一致第三方版本号. 在运行 Go 应用程序的时候,你无法保证其它人与你所期望依赖的第三方库是相同的版本,也就是说在项目依赖库的管理上,你无法保证所有人的依赖版本都一致。
  3. 无法指定当前项目引用的第三方版本号. 你没办法处理 v1、v2、v3 等等不同版本的引用问题,因为 GOPATH 模式下的导入路径都是一样的,都是github.com/foo/bar

三、Go Modules模式创建项目

我们接下来用Go Modules的方式创建一个项目, 建议为了与GOPATH分开,不要将项目创建在GOPATH/src下.

1.go mod命令

命令作用
go mod init生成 go.mod 文件
go mod download下载 go.mod 文件中指明的所有依赖
go mod tidy整理现有的依赖
go mod graph查看现有的依赖结构
go mod edit编辑 go.mod 文件
go mod vendor导出项目所有的依赖到vendor目录
go mod verify校验一个模块是否被篡改过
go mod why查看为什么需要依赖某模块

2.go mod环境变量

可以通过 go env 命令来进行查看

$ go env
GO111MODULE="auto"
GOPROXY="https://proxy.golang.org,direct"
GONOPROXY=""
GOSUMDB="sum.golang.org"
GONOSUMDB=""
GOPRIVATE=""
...
  • GO111MODULE
    Go语言提供了 GO111MODULE这个环境变量来作为 Go modules 的开关,其允许设置以下参数:
    • auto:只要项目包含了 go.mod 文件的话启用 Go modules,目前在 Go1.11 至 Go1.14 中仍然是默认值。
    • on:启用 Go modules,推荐设置,将会是未来版本中的默认值。
    • off:禁用 Go modules,不推荐设置。

设置GO111MODULE;

$ go env -w GO111MODULE=on
  • GOPROXY
    这个环境变量主要是用于设置 Go 模块代理(Go module proxy),其作用是用于使 Go 在后续拉取模块版本时直接通过镜像站点来快速拉取。
    GOPROXY 的默认值是:https://proxy.golang.org,direct
    proxy.golang.org国内访问不了,需要设置国内的代理.
    • 阿里云
      https://mirrors.aliyun.com/goproxy/
    • 七牛云
      https://goproxy.cn,direct

设置GOPROXY:

$ go env -w GOPROXY=https://goproxy.cn,direct

GOPROXY 的值是一个以英文逗号 “,” 分割的 Go 模块代理列表,允许设置多个模块代理,假设你不想使用,也可以将其设置为 “off” ,这将会禁止 Go 在后续操作中使用任何 Go 模块代理。

$ go env -w GOPROXY=https://goproxy.cn,https://mirrors.aliyun.com/goproxy/,direct

而在刚刚设置的值中,我们可以发现值列表中有 direct标识,它又有什么作用呢?
实际上 “direct” 是一个特殊指示符,用于指示 Go 回源到模块版本的源地址去抓取(比如 GitHub 等),场景如下:当值列表中上一个 Go 模块代理返回 404 或 410 错误时,Go 自动尝试列表中的下一个,遇见 “direct” 时回源,也就是回到源地址去抓取,而遇见 EOF 时终止并抛出类似 “invalid version: unknown revision…” 的错误。

  • GOSUMDB
    它的值是一个 Go checksum database,用于在拉取模块版本时(无论是从源站拉取还是通过 Go module proxy 拉取)保证拉取到的模块版本数据未经过篡改,若发现不一致,也就是可能存在篡改,将会立即中止。
    GOSUMDB 的默认值为:sum.golang.org,在国内也是无法访问的,但是 GOSUMDB 可以被 Go 模块代理所代理(详见:Proxying a Checksum Database)。
    因此我们可以通过设置 GOPROXY 来解决,而先前我们所设置的模块代理 goproxy.cn 就能支持代理 sum.golang.org,所以这一个问题在设置 GOPROXY 后,你可以不需要过度关心。
    另外若对 GOSUMDB 的值有自定义需求,其支持如下格式:

    • 格式 1:<SUMDB_NAME>+<PUBLIC_KEY>
    • 格式 2:<SUMDB_NAME>+<PUBLIC_KEY> <SUMDB_URL>
    • 也可以将其设置为“off”,也就是禁止 Go 在后续操作中校验模块版本
  • GONOPROXY/GONOSUMDB/GOPRIVATE
    这三个环境变量都是用在当前项目依赖了私有模块,例如像是你公司的私有 git 仓库,又或是 github 中的私有库,都是属于私有模块,都是要进行设置的,否则会拉取失败。
    更细致来讲,就是依赖了由 GOPROXY 指定的 Go 模块代理或由 GOSUMDB 指定 Go checksum database 都无法访问到的模块时的场景。

一般建议直接设置 GOPRIVATE,它的值将作为 GONOPROXY 和 GONOSUMDB 的默认值,所以建议的最佳姿势是直接使用 GOPRIVATE。
并且它们的值都是一个以英文逗号 “,” 分割的模块路径前缀,也就是可以设置多个,例如:

$ go env -w GOPRIVATE="git.example.com,github.com/eddycjy/mquote"

设置后,前缀为 git.xxx.comgithub.com/eddycjy/mquote 的模块都会被认为是私有模块。
如果不想每次都重新设置,我们也可以利用通配符,例如:

$ go env -w GOPRIVATE="*.example.com"

这样子设置的话,所有模块路径为 example.com 的子域名(例如:git.example.com)都将不经过 Go module proxy 和 Go checksum database,需要注意的是不包括 example.com 本身。

  • 以上的所有环境变量配置,如果执行命令后未修改成功,都可以直接在配置文件中修改:
vim ~/.bashrc

在这里插入图片描述
修改完后需加载配置文件:

source .bashrc

在这里插入图片描述

3.使用Go Modules初始化项目

  • 创建项目目录
    使用Go Modules创建项目无需在GOPATH下创建文件夹
    在这里插入图片描述
    在这里插入图片描述
  • 执行Go modules 初始化
    在这里插入图片描述
    在这里插入图片描述
    执行完go mod初始化后,项目文件夹中会出现一个go.mod文件;
    go.mod文件内容:包括模块名称和go的版本
    在这里插入图片描述

go mod初始化:

go mod init 模块名称

模块名称是自定义的,决定之后的代码在导入本包的时候import的名称;

  • 接下来写一段代码,导入一个现成的包:
package mainimport ("fmt""github.com/aceld/zinx/ziface""github.com/aceld/zinx/znet"
)// ping test 自定义路由
type PingRouter struct {znet.BaseRouter
}// Ping Handle
func (this *PingRouter) Handle(request ziface.IRequest) {//先读取客户端的数据fmt.Println("recv from client : msgId=", request.GetMsgID(),", data=", string(request.GetData()))//再回写ping...ping...pingerr := request.GetConnection().SendBuffMsg(0, []byte("ping...ping...ping"))if err != nil {fmt.Println(err)}
}func main() {//1 创建一个server句柄s := znet.NewServer()//2 配置路由s.AddRouter(0, &PingRouter{})//3 开启服务s.Serve()
}

我们先不要关注代码本身,我们看当前的main.go也就是我们的aceld/modules_test项目,是依赖一个叫github.com/aceld/zinx库的, znet和ziface只是zinx的两个模块;

  • 接下来我们在$HOME/aceld/modules_test,本项目的根目录执行go get指令
    在这里插入图片描述
go get github.com/aceld/zinx/znet

不主动执行go get指令,也会自动下载

  • 我们会看到 我们的go.mod被修改,同时多了一个go.sum文件.
  • 查看go.mod文件
    在这里插入图片描述
    这里面的关键字:
    • module: 用于定义当前项目的模块路径
    • go:标识当前Go版本.即初始化版本
    • require: 当前项目依赖的一个特定的必须版本
    • // indirect: 示该模块为间接依赖,也就是在当前应用程序中的 import 语句中,并没有发现这个模块的明确引用,有可能是你先手动 go get 拉取下来的,也有可能是你所依赖的模块所依赖的.我们的代码很明显是依的"github.com/aceld/zinx/znet""github.com/aceld/zinx/ziface",所以就间接的依赖了github.com/aceld/zinx
  • 查看go.sum文件
    在第一次拉取模块依赖后,会发现多出了一个go.sum文件,其详细罗列了当前项目直接或间接依赖的所有模块版本,并写明了那些模块版本的 SHA-256 哈希值以备 Go 在今后的操作中保证项目所依赖的那些模块版本不会被篡改
    在这里插入图片描述
    我们可以看到一个模块路径可能有如下两种:
    h1:hash情况:
    在这里插入图片描述
    go.mod hash情况:
    在这里插入图片描述
    h1 hash 是 Go modules 将目标模块版本的 zip 文件开包后,针对所有包内文件依次进行 hash,然后再把它们的 hash 结果按照固定格式和算法组成总的 hash 值。
    而 h1 hash 和 go.mod hash 两者,要不就是同时存在,要不就是只存在 go.mod hash。那什么情况下会不存在 h1 hash 呢,就是当 Go 认为肯定用不到某个模块版本的时候就会省略它的 h1 hash,就会出现不存在 h1 hash,只存在 go.mod hash 的情况。

4.修改模块的版本依赖关系

为了作尝试,假定我们现在对zinx版本作了升级, 由zinx v1.2.1升级到zinx v1.2.2(注意zinx是一个没有打版本tag打第三方库,如果有的版本号是有tag的,那么可以直接对应v后面的版本号即可)
那么,如果我们想获得1.2.1版本的包,该如何执行命令呢?

  • 先回到$HOME/aceld/modules_test,本项目的根目录执行
[lmx@lmx-CentOS modules_go]$ go get github.com/aceld/zinx/znet@v1.2.1
go: downloading github.com/aceld/zinx v1.2.1
go: downgraded github.com/aceld/zinx v1.2.2 => v1.2.1

go get package@version在包后面加上@就可以下载指定版本的包;
如果要升级最新版本,可以执行

go get -u package

会更新所有依赖该包的版本

这样我们,下载了之前版本的zinx, 版本是v1.2.1

  • go.mod中:
    在这里插入图片描述
    我们会看到,当我们执行go get 的时候, 会自动的将本地将当前项目的require更新了.变成了指定版本的依赖.
  • 我们想用一个最新版本的zinx. 来修改当前zinx模块的依赖版本号
    目前我们在$GOPATH/pkg/mod/github.com/aceld下,已经有了两个版本的zinx库
    在这里插入图片描述
  • 目前,我们的项目依赖的是zinx@v1.2.1这个不是最新版, 我们要改成最新版本zinx@v1.2.2.
  • 回到/goProject/modules_go项目目录下,执行
$ go mod edit -replace=zinx@v1.2.1=zinx@v1.2.2
  • 然后我们打开go.mod查看一下
    在这里插入图片描述
  • 这里出现了replace关键字.用于将一个模块版本替换为另外一个模块版本

四、Go Modules下import导本地包

1.所有包在同一项目目录下

一个文件夹中只能有一个包,多个包会报错
在这里插入图片描述

  • 代码结构:
    在这里插入图片描述
  • go.mod
module function_gogo 1.20
  • Lib1.go
    Initlib1包
package Initlib1import "fmt"// lib1提供的API
func lib1Test() {fmt.Println("lib1Test()...")
}func init() {fmt.Println("lib1")
}
  • Lib2.go
    Initlib2包
package Initlib2import "fmt"// lib2提供的API
func lib2Test() {fmt.Println("lib2Test()...")
}func init() {fmt.Println("lib2")
}
  • main.go
    main包
    • 在使用Go Modules导入本地包的时候,在包名的前面需要指定模块名才可以导入
      比如上面的go.mod中模块名是function_go,导入包的路径就是function_go/InitLib1,是模块名/文件夹名
    • 在导入了包之后,需要调用包中的方法,可以直接包名.方法()
package mainimport ("function_go/InitLib1""function_go/InitLib2"
)func main() {InitLib1.Lib1Test()InitLib2.Lib2Test()
}
  • 运行结果
lib1
lib2
libmain init
libmian main

2.import导入的包与main包不在同一个路径下

  • 项目结构:
    在这里插入图片描述
  • fun_gofunction_go是两个不同的模块,如果要在fun_go下的main.go中导入function_go/InitLib1包,也需要指定模块名
package mainimport ("fmt""function_go/InitLib1" // 指定模块名
)func main() {InitLib1.Lib1Test()fmt.Println("go")
}

在这里插入图片描述

3.import导入本地包的格式

项目结构:
在这里插入图片描述

  • go.mod
module expressiongo 1.20
  • switch.go
package Switchimport "fmt"func Switch() {grade := 'B'marks := 90switch marks {case 90:grade = 'A'case 80:grade = 'B'case 70, 60, 50:grade = 'C'default:grade = 'D'}switch {case grade == 'A':fmt.Println("优秀")case grade == 'B':fmt.Println("良好")case grade == 'C':fmt.Println("及格")default:fmt.Println("不及格")}fmt.Println("你的等级是:", grade)
}
  • main.go
package mainimport (Switch "expression/switch""fmt"
)func main() {Switch.Switch()fmt.Println("ll")
}

在main包中导入同一模块下的Switch包,导入的格式一定是模块名/文件夹名,模块名后面跟的是包的路径,不是包名,写包名会导致报错,所以文件夹的名字最好和包名一致,这样方便不容易出错

  • 修改文件夹名之后:
    在这里插入图片描述
  • main.go
package mainimport ("expression/Switch" //模块名/包的文件夹名"fmt"
)func main() {Switch.Switch()fmt.Println("ll")
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/595764.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何写出一份优秀的简历?(求职必知)

你需要知道的事 简历是对自己职场的总结和概括&#xff0c;是通往下一段职业经历的敲门砖和 垫脚石。 因此&#xff0c;一份好的简历应该突出应聘者的优势&#xff0c;并引起企业方的好奇心。 知己知彼&#xff0c;百战百胜&#xff0c;求职者只有了解自己&#xff0c;以及了解…

大数据应用开发2-Scala语言各个环境配置

一、首先安装JDK1.8版本(简单过一下) 1.下载与安装 下载Java1.8 地址&#xff1a;Java Downloads | Oracle 中国 点击跳转&#xff08;下载需要登录甲骨文账号&#xff09; 下载完成运行 修改安装目录&#xff08;两个都要改&#xff09; 复制第一次修改的安装目录 2.配置环…

立仪科技光谱共焦位移传感器:应用领域的广泛性

在科技日新月异的今天&#xff0c;光谱共焦位移传感器以其精确、稳定的特性&#xff0c;在各个领域得到了广泛的应用。本文将详细介绍光谱共焦位移传感器的应用情况&#xff0c;以期让大家对其有更深入的了解。我们来理解一下什么是光谱共焦位移传感器。 它是一种通过测量物体表…

cmd命令启动C# windows服务程序

因为Process.Manage.Service.exe程序为Windows服务程序&#xff0c;不能直接双击打开&#xff0c;所以需要借助windows系统自带InstallUtil.exe程序来启动它。 以管理员身份运行cmd命令控制台窗口 输入命令进入到InstallUtil.exe程序所在的文件夹 cd C:\Windows\Microsoft.NET…

【EI会议征稿通知】第三届电子与集成电路技术国际学术会议(EICT 2024)

第三届电子与集成电路技术国际学术会议&#xff08;EICT 2024&#xff09; 2024 3rd International Conference on Electronics and Integrated Circuit Technology 第三届电子与集成电路技术国际学术会议&#xff08;EICT 2024&#xff09;将于2024年4月12至14日在南昌市举行…

【电路笔记】-超级电容器

超级电容器 文章目录 超级电容器1、概述2、对电容器充电3、超级电容构造4、超级电容器示例15、超级电容器能量6、总结 超级电容器是能够存储大量电荷的电能存储设备。 1、概述 与以热的形式耗散能量的电阻器不同&#xff0c;理想的超级电容器不会损失能量。 我们还看到&#x…

【ITK库学习】使用itk库进行图像配准:变换Transform(三)

目录 1、itkAffineTransform 仿射变换2、itkBSplineDeformableTransform B样条可变形变换 1、itkAffineTransform 仿射变换 该类实现向量空间的仿射变换&#xff08;例如空间坐标&#xff09; 此类允许定义和操作n维仿射空间&#xff08;及其关联的向量空间&#xff09;对其自…

班主任是班级工作的什么人

在我们的学习生涯中&#xff0c;班主任是一个不可或缺的角色。他不仅是我们学术上的指导者&#xff0c;更是我们成长路上的引路人。 是班级的掌舵者。一个班级就像一艘船&#xff0c;航行在知识的海洋中。班主任就是这艘船的船长&#xff0c;他们带领着我们向着目标前进&#x…

【办公软件】修改U盘的默认盘符

在工作中我们可能会因为有一些大型软件设置了库文件路径&#xff08;如Z盘&#xff09;。在家办公时通过U盘的方式将库拷入在U盘中&#xff0c;但是到家里的电脑上&#xff0c;U盘插入后会默认一个盘符&#xff08;如E盘&#xff09;&#xff0c;那么应该怎么操作呢&#xff1f…

国产化软硬件升级之路:πDataCS 赋能工业软件创新与实践

在国产化浪潮的推动下&#xff0c;基础设施软硬件替换和升级的需求日益增长。全栈国产化软硬件升级替换已成为许多领域中的必选项&#xff0c;也引起了数据库和存储领域的广泛关注。近年来&#xff0c;虽然涌现了许多成功的替换案例&#xff0c;但仍然面临着一些问题。 数据库…

判断线性相关性

线性相关是线性代数中的一个重要概念&#xff0c;用于描述向量或向量组之间的线性关系。以下是判断向量组是否线性相关的几种方法&#xff1a; 1. **根据定义判断**&#xff1a; - 如果存在一组不全为零的系数&#xff0c;使得这些系数与对应的向量组相乘后相加等于零向量&a…

如何为项目创建高效的项目进度表?

项目管理是一项负有巨大责任的工作&#xff0c;涉及到完成项目所需的大量流程和任务。如果没有任务和责任的线路图&#xff0c;很容易就偏离方向&#xff0c;无法了解项目每个阶段需要完成的任务。这就是为什么项目进度表是成功执行项目的核心所在。 什么是项目进度表&#xff…

MSVCR100.dll丢失,程序无法启动,快速修复,亲测有效

很多用户&#xff0c;在日常使用电脑的过程中都遇到过&#xff0c;电脑报错“程序由于缺失MSVCR100.dll文件&#xff0c;无法启动&#xff0c;需要重新安装解决”&#xff0c;不少用户卸载软件重装后&#xff0c;还是报错&#xff0c;那么应该怎么解决呢&#xff1f; 首先&…

FastApi-快速入门1

FastAPI 是一个用于构建 API 的现代、快速&#xff08;高性能&#xff09;的 web 框架&#xff0c;使用 Python 3.8 并基于标准的 Python 类型提示。 关键特性: 快速&#xff1a;可与 NodeJS 和 Go 并肩的极高性能&#xff08;归功于 Starlette 和 Pydantic&#xff09;。最快…

「实验记录」CS144 Lab1 StreamReassembler

目录 一、Motivation二、SolutionsS1 - StreamReassembler的对外接口S2 - push_substring序列写入ByteStream 三、Result四、My Code五、Reference 一、Motivation 我们都知道 TCP 是基于字节流的传输方式&#xff0c;即 Receiver 收到的数据应该和 Sender 发送的数据是一样的…

vue-cli项目中vue.config.js的配置

vue-cli项目中vue.config.js的配置 一、直接上代码 一、直接上代码 let path require(path) let glob require(glob)function resolve(dir) {return path.join(__dirname, src/${dir}) }module.exports {pages: {index: {// page 的入口entry: src/main.js,// 模板来源temp…

Java学习笔记

Java学习笔记 java发展先按黑马尚硅谷的路线来吧部分项目代码参考 第一阶段&#xff1a;JavaSE基础9天 中文API可以看菜鸟教程里的 java发展 jdk8后最大改变&#xff1a;lambda&#xff0c;stream 先按黑马尚硅谷的路线来吧 https://blog.csdn.net/qq_40991313/article/deta…

为什么需要在bean上使用@EqualsAndHashCode(callSuper = true)这个注解

我们还是写一个案例&#xff0c;来探讨它的作用。 写三个类&#xff0c;一个是子类Child.class&#xff0c;一个是父类Person.class&#xff0c;一个是测试类Test.class Person父类很简单&#xff0c;就一个属性code&#xff1b; Child子类也很简单&#xff0c;继承了父类之后…

计算机组成原理-总线标准(系统总线 局部总线 设备总线)

文章目录 总览例子总线标准的基本概念系统总线标准局部总线标准设备总线标准对比小结为何串行总线取代并行总线 总览 例子 总线标准的基本概念 北桥芯片速度大于南桥芯片 系统总线标准 ISA和EISA都是并行总线 Intel提出了FBS总线标准比EISA和ISA快&#xff0c;后来又提出来…

LeetCode(31) 下一个排列

整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。 例如&#xff0c;arr [1,2,3] &#xff0c;以下这些都可以视作 arr 的排列&#xff1a;[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。 整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地&#xf…