Go后端开发 -- Go Modules

news2024/9/20 7:53:41

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 main

import (
	"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...ping
	err := 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_go

go 1.20
  • Lib1.go
    Initlib1包
package Initlib1

import "fmt"

// lib1提供的API
func lib1Test() {
	fmt.Println("lib1Test()...")
}

func init() {
	fmt.Println("lib1")
}
  • Lib2.go
    Initlib2包
package Initlib2

import "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 main

import (
	"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 main

import (
	"fmt"
	"function_go/InitLib1" // 指定模块名
)

func main() {
	InitLib1.Lib1Test()
	fmt.Println("go")
}

在这里插入图片描述

3.import导入本地包的格式

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

  • go.mod
module expression

go 1.20
  • switch.go
package Switch

import "fmt"

func Switch() {
	grade := 'B'
	marks := 90

	switch 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 main

import (
	Switch "expression/switch"
	"fmt"
)

func main() {
	Switch.Switch()
	fmt.Println("ll")
}

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

  • 修改文件夹名之后:
    在这里插入图片描述
  • main.go
package main

import (
	"expression/Switch" //模块名/包的文件夹名
	"fmt"
)

func main() {
	Switch.Switch()
	fmt.Println("ll")
}

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

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

相关文章

快速实现前后端表单交互(minui)

&#xff08;1&#xff09;使用minui快速生成表单 &#xff08;2&#xff09;修改样式&#xff0c;将生成的html文件发送给后端 &#xff08;3&#xff09;前后端交互&#xff08;后端如何处理不太清楚&#xff09; 表单初始化&#xff1a;新增修改&#xff08;包括查看&…

如何远程修改plc程序?

​在工业自动化领域中&#xff0c;PLC&#xff08;可编程逻辑控制器&#xff09;是不可或缺的一部分。然而&#xff0c;传统方式下修改PLC程序需要亲临现场&#xff0c;这不仅耗时&#xff0c;还增加了成本。那么有没有一种更加高效、便捷的方法呢&#xff1f;答案是肯定的&…

【REST2SQL】03 GO读取JSON文件

REST2SQL需要一些配置信息&#xff0c;用JSON文件保存&#xff0c;比如config.json 1 创建config.json配置文件 {"hostPort":"localhost:5217","connString":"oracle://blma:5217127.0.0.1:1521/CQYH","_oracle":"ora…

6591A便携式光伏组串测试仪

01 6591A便携式光伏组串测试仪 产品综述&#xff1a; 6591A主要用于1500V光伏组串的测试&#xff0c;能够方便、快速的测试1500V光伏组串在自然光照下的工作特性&#xff0c;可为太阳能电站设计、验收、维护提供测试保障&#xff0c;是电站建设单位、质检部门、生产厂家、科研…

Navicat 技术干货 | 聚合查询的介绍

基础 SQL 查询可以检索、插入、更新和删除记录&#xff0c;而聚合查询可通过提供求和、平均值或最大/最小值等的大型结果集&#xff0c;将数据库交互提升到一个新的水平。本文中&#xff0c;我们将探索聚合 SQL 查询的基础知识&#xff0c;并研究如何有效的利用他们来分析和汇总…

边坡安全监测预警系统——高效率

安装边坡安全监测预警系统的原因是多方面的&#xff0c;涉及到社会效益、经济效益和环境效益。随着国家基础设施建设的快速发展&#xff0c;边坡安全监测预警系统的需求越来越迫切。 边坡安全监测预警系统对于保障人民生命财产安全具有重要意义。在山区、丘陵地带&#xff0c;边…

牛客网面试题知识点记录-03

1.题目讲解重写后子类调用父类的方法总结&#xff1a;当子类重写了父类方法A&#xff0c;父类方法直接调用被重写的父类方法后&#xff0c;调用的是子类的重写的父类方法A。 class Test {public static void main(String[] args) {System.out.println(new B().getValue());}st…

安科瑞电化学储能电能管理系统解决方案——安科瑞 顾烊宇

1 概述 在我国新型电力系统中&#xff0c;新能源装机容量逐年提高&#xff0c;但是新能源比如光伏发电、风力发电是不稳定的能源&#xff0c;所以要维持电网稳定&#xff0c;促进新能源发电的消纳&#xff0c;储能将成为至关重要的一环&#xff0c;是分布式光伏、风电等新能源消…

Java中的异常如何处理?

在Java编程中&#xff0c;异常是一种在程序执行期间发生的意外情况。学会处理异常是编写健壮、可靠程序的关键之一。 为什么需要异常处理&#xff1f; 异常处理允许程序在发生错误时进行优雅而有序的处理&#xff0c;而不是导致程序崩溃。这有助于提高程序的可维护性和用户体…

Alibaba Cloud Linux镜像操作系统超详细测评!兼容CentOS

Alibaba Cloud Linux是基于龙蜥社区OpenAnolis龙蜥操作系统Anolis OS的阿里云发行版&#xff0c;针对阿里云服务器ECS做了大量深度优化&#xff0c;Alibaba Cloud Linux由阿里云官方免费提供长期支持和维护LTS&#xff0c;Alibaba Cloud Linux完全兼容CentOS/RHEL生态和操作方式…

Vue: 多个el-select不能重复选择相同属性

一、场景 1.需求&#xff1a; 用户可自由选择需要修改的对象并同时修改多个属性&#xff0c;需要校验修改对象不能重复选择&#xff0c;但是可供修改属性是固定的 2.目标效果&#xff1a; 二、实现 1.主要代码&#xff1a; <template><el-selectv-model"se…

k8s pod基础 1

发布和yaml文件的初步了解。 pod&#xff1a;是k8s中最小的资源管理组件。 pod也是最小化运行容器化的应用的资源管理对象。 pod是一个抽象的概念&#xff0c;可以理解为一个或者多个容器化应用的集合。 在一个pod当中运行一个容器是最常用的方式。 在一个pod当中可以同时…

深度思考,AI项目的人工智能到底引领的是什么?

项目深度思考&#xff0c;人工智能到底引领的是什么&#xff1f; 人工智能引领技术之舞&#xff1a;项目深度思考项目背景&#xff1a;人工智能的魔法时代技术选择的深度思考&#xff1a;AI大决战团队协作的深度思考&#xff1a;AI联盟大会用户体验的深度思考&#xff1a;AI之光…

鸿蒙HarmonyOs:为什么不支持热更新?

学习了一段时间的鸿蒙开发&#xff0c;发现鸿蒙开发还是比较简单的&#xff0c;今天突然心血来潮&#xff0c;研究了一下鸿蒙热更新&#xff0c;最终得出的结论是鸿蒙暂时不支持热更新。 鸿蒙app开发主要是利用的ArkTs语言&#xff0c;ArkTs又是基于TypeScript语言的&#xff0…

2024年MySQL学习指南(二),探索MySQL数据库,掌握未来数据管理趋势

文章目录 前言4. DDL- 操作数据库4.1 查询4.2 创建数据库4.3 删除数据库4.4 使用数据库 5. DDL- 操作数据表5.1 数据类型5.2 查询表5.3 创建表5.4 删除表5.5 修改表 6. 实战案例详解 前言 接上一篇文章【2024年MySQL学习指南&#xff08;一&#xff09;】 4. DDL- 操作数据库 …

ROS学习记录:在ROS中用C++实现激光雷达避障

前言 本文建立在成功获取激光雷达数据的基础上&#xff0c;详细参考 在ROS中用C实现获取激光雷达的数据 一、实现思路 二、在VScode中打开之前编写好的lidar_node.cpp 三、在lidar_node.cpp中写入如下代码 #include <ros/ros.h> #include <std_msgs/String.h> …

如何使用 AI 准备雅思口语考试

问题 雅思口语考试分为以下几个部分&#xff1a; 第 1 部分&#xff1a;考官将要求考生自我介绍并询问他们一些个人问题&#xff0c;例如他们的身份、兴趣和爱好。 第 2 部分&#xff1a;考官会给考生一张任务卡、一支铅笔和一些做笔记的纸。任务卡将提供一个主题和一些关键问…

【分布式系统学习】之分布式入门理解

目录 1、问&#xff1a;谈谈对分布式系统的理解2、问&#xff1a;那分布式系统环境下各自有什么优缺点&#xff1f;2.1 优点2.2 缺点 总结&#xff1a; 1、问&#xff1a;谈谈对分布式系统的理解 答&#xff1a; 分布式系统通俗来说&#xff1a;就是将计算能力和数据存储能力分…

springboot 2.7 oauth server配置源码走读一

springboot 2.7 oauth server配置源码走读 入口&#xff1a; 上述截图中的方法签名和OAuth2AuthorizationServerConfiguration类中的一个方法一样&#xff0c;只不过我们自己的配置类优先级比spring中的配置类低&#xff0c;算是配置覆盖&#xff0c;看下图所示&#xff1a; …

everything 本地文件搜索工具 完胜WIndows搜索 速度99% 超级给力

"Everything" 是一个 Windows 平台上的免费软件&#xff0c;它是一款功能强大的本地文件搜索工具。它允许用户在计算机上快速而准确地搜索文件和文件夹。以下是一些 "Everything" 的主要特点&#xff1a; 实时搜索&#xff1a; "Everything" 提供…