从零基础学Go(三)——什么是Go.mod文件

简介📃

Go包的概念

o语言中的包是一组具有相关功能的Go源码文件的集合。它们被组织在一起形成一个独立的单元,供其他程序引用和使用。每个包都有一个唯一的包名,并以关键字package开头。一个包可以被其他包引用,也可以引用其他包中的代码。通过这种方式,Go语言中的包实现了代码的模块化,便于管理和复用。

每个包通常由多个文件组成,这些文件的命名必须以.go为后缀。在同一个包中的所有文件必须使用相同的包名,并且它们的代码都必须在同一个目录下。一个包的代码可以包含类型定义、变量、常量、函数和方法等。

Go依赖管理的概念

依赖管理是现代软件开发中不可避免的一部分。它用于解决在一个项目中使用其他库和框架的问题。在Go语言中,可以通过导入其他包来引用外部代码。但是,Go语言自带的包管理机制比较简单,无法满足复杂项目的需求,因此需要使用第三方的包管理工具来解决这个问题。

在Go语言中,常见的依赖管理工具有depgo mod等。它们可以自动下载、更新、管理项目依赖的包,同时保证项目的可重复性和稳定性。这些工具还可以管理依赖包的版本、依赖关系、引入和删除等操作。depgo mod,在一定程度上相当于maven之于Java,composer之于PHP,dep是go语言官方的一个包管理工具。

什么是dep

相比较go get而言,dep可以直接给引入的第三方包一个专门的目录,并且可以专门制定一个配置文件,控制go项目所引入的包,版本以及其他依赖关系。

dep这个项目放在golang官方的github中:https://github.com/golang/dep

官方对于dep的解释是:dep is the official experiment, but not yet the official tool. 也就是说,dep目前还处于试验阶段,还并没有成为一个官方意义上的工具。毕竟go语言还很年轻,但是这也充分的证明了go语言的生态圈十分丰富。相较于dep的年轻,Go.mod则更加成熟,因此我们本篇着重于介绍Go.mod的使用。

什么是go.mod

Go.mod是Golang1.11版本新引入的官方包管理工具用于解决之前没有地方记录依赖包具体版本的问题,方便依赖包的管理。

Go.mod其实就是一个Modules,关于Modules的官方定义为:

Modules是相关Go包的集合,是源代码交换和版本控制的单元。go命令直接支持使用Modules,包括记录和解析对其他模块的依赖性。Modules替换旧的基于GOPATH的方法,来指定使用哪些源文件。

Modules和传统的GOPATH不同,不需要包含例如src,bin这样的子目录,一个源代码目录甚至是空目录都可以作为Modules,只要其中包含有go.mod文件。

Go mod的使用✔️

如何开启使用

  1. 首先将go的版本升级为1.11以上
  2. 设置GO111MODULE,即在命令行终端执行下面代码
go env -w GO111MODULE=on 

GO111MODULE有三个值:off, on和auto(默认),说明如下:

  • GO111MODULE=off,关闭go mod,寻找依赖包通过旧版本的vendor目录或者GOPATH目录来查找
  • GO111MODULE=on,开启go mod,寻找依赖包不会去GOPATH目录下查找
  • GO111MODULE=auto,默认值,go将会根据当前目录来决定是否启用module功能。这种情况下可以分为两种情形:
    • 当前目录在GOPATH/src之外且该目录包含go.mod文件
    • 当前文件在包含go.mod文件的目录下面。

文件的基本结构

module example.com/mymodule

go 1.22.5

require (
    github.com/example/package v1.2.3
    // additional dependencies
)

replace (
    // replacement rules
)

## 
  • module: 定义模块的名称,通常是项目的导入路径。该路径也用于唯一标识模块。
  • go: 指定项目的最小Go语言版本,确保项目在指定版本及以上的Go环境中可以正确构建。
  • require: 列出模块的直接依赖关系及其版本。这里 github.com/example/package 是一个示例依赖,指定了版本 v1.2.3
  • replace: 指定替代或替换规则,用于本地调试或使用自定义的包。

基本步骤

  • 初始化项目:使用go mod init命令来初始化一个新的Go模块,生成一个go.mod文件,用于管理项目依赖。
  • 添加依赖:使用go get命令来添加一个新的依赖包到项目中。
  • 更新依赖:使用go get -u命令来更新依赖包到最新版本。
  • 删除依赖:使用go mod tidy命令来删除项目中没有用到的依赖包。
  • 查看依赖:使用go list命令来查看当前项目的依赖包

常见命令

  • go mod init:初始化一个新的Go模块,用于开始新的项目。可以在初始化时指定模块名称和版本号。
  • go mod tidy:整理并删除项目中未使用的依赖项。如果你在项目中添加或删除了依赖项,可以使用该命令更新依赖项列表。
  • go mod vendor:将依赖项复制到项目的vendor目录中,以便离线构建。
  • go mod download:下载依赖项,但不会安装它们。这个命令可以用于预先下载依赖项,以便之后进行离线构建。
  • go mod verify:验证依赖项的完整性和正确性。如果依赖项已经下载但是被修改或损坏了,那么就会发出警告。
  • go mod graph:以依赖项图的形式打印模块依赖关系。
  • go mod why:解释为什么需要依赖项。

例如,如果你想在你的项目中使用gin框架,可以使用以下命令将其添加为依赖项:

go get -u github.com/gin-gonic/gin

该命令会将gin框架下载到你的$GOPATH/pkg/mod目录中,并将其添加到go.mod文件中。

Vendor目录详解❔️

在Go语言中,vendor 目录是用于存放项目的依赖项的本地拷贝的目录。使用 vendor 目录的主要目的是为了在项目中固定依赖项的版本,以确保在不同环境中构建时使用相同的代码。

这个目录的作用主要有以下几点:

  • 依赖管理vendor 目录允许开发者将项目依赖的第三方库的代码直接包含在项目中,从而避免依赖外部的版本控制系统。
  • 版本控制:通过在vendor目录中锁定依赖的特定版本,可以确保项目在不同环境下的一致性,防止因依赖库的更新导致项目出现问题。
  • 兼容性vendor 目录使得项目可以在没有网络连接的情况下构建,这对于在没有互联网访问的环境中工作非常有用。
  • 安全性:使用vendor目录可以减少对外部源的依赖,降低因依赖库被恶意修改而带来的安全风险。
  • 构建速度:由于依赖库已经被包含在项目中,构建时不需要从外部下载,这可以加快构建速度。
  • 依赖隔离vendor目录允许项目拥有自己的依赖版本,即使这些依赖与项目之外的其他项目使用的版本不同,也不会产生冲突。

开发者可以通过运行go mod vendor命令来将依赖库的代码复制到vendor目录中。此外,还可以使用go mod tidy命令来同步模块依赖与go.mod文件,确保vendor目录中的依赖是最新的。

注意事项

  • 优先级: 在使用 vendor 目录的情况下,Go 会优先使用 vendor 目录中的依赖项,而不是从远程下载。这确保了版本的稳定性。

  • 推荐使用: 尽管 Go 模块已经成为推荐的依赖管理方式,但 vendor 目录仍然是一种可行的方式,特别是对于需要离线构建或者对特定版本有要求的项目。

  • **不推荐修改:**通常情况下,不建议手动修改 vendor 目录中的代码。修改应当通过修改依赖项的源代码或者更新依赖项版本来进行。

替代模块replace详解❔️

Go的模块系统提供了一种强大的依赖管理方式,其中replace指令是一个重要的特性,用于指定模块的替代版本。以下是replace指令的一些详解:

  • 用途replace指令允许开发者指定一个模块的替代版本,这可以是不同的版本号、不同的模块路径,甚至是本地路径。

  • 语法replace指令的基本语法如下:

    gomodule example.com/myproject
    
    // 替代模块的语法
    replace example.com/somemodule v1.2.3 => example.com/someothermodule v1.3.0
    
  • 替代版本: 使用replace可以指定一个模块的替代版本,例如,如果你的项目依赖example.com/somemodulev1.2.3版本,但你想要使用v1.3.0版本,你可以在go.mod文件中添加相应的replace指令。

  • 替代模块路径: 除了版本替代,replace还可以用于将一个模块路径映射到另一个路径。这在模块被重构或迁移到新的路径时非常有用。

  • 本地替代replace指令还可以用于将模块映射到本地路径,这对于开发中的模块或者私有模块非常有用。例如:

    go
    replace example.com/myprivatemodule => ../myprivatemodule
    
  • 版本解决: 当Go工具链处理模块依赖时,它会首先查找go.mod文件中的replace指令,然后根据这些指令来解析和下载模块。

  • 兼容性: 使用replace指令时,需要确保替代的模块与原始模块在API层面是兼容的,否则可能会导致编译错误或运行时问题。

  • 限制replace指令不能用于替代Go标准库中的模块,因为标准库的模块路径是固定的。

  • 使用场景

    • 当一个模块的特定版本存在已知问题,而更新的版本已经修复了这些问题时。
    • 当需要使用尚未正式发布的新版本时。
    • 当需要将依赖从公共模块路径替换为私有模块路径时。
  • 注意事项

    • 使用replace指令时,应该谨慎,因为它可能会影响项目的构建和运行。
    • 在团队协作中,确保所有开发者都了解replace指令的使用,以避免构建不一致的问题。

小试牛刀🗡️

我们首先用vscode打开我们在上一篇文章中写过的hello.go文件,此时界面如下图所示:

在这里插入图片描述

假设我们现在想给我们的项目添加一个轻量级的web框架gin框架(类似于Java中的springboot)

无包管理情况

假设没有使用go mod,我们需要在命令行终端首先执行下列shell命令

go get -u github.com/gin-gonic/gin

接下来在代码的import部分中添加对于这个框架的引用

// 声明main包,表明当前是一个可执行程序

package main

// 导入部分

import (

  // 导入内置的fmt包

  "fmt"

  // 导入外部包gin

  "github.com/gin-gonic/gin"

)

// main函数是程序执行的入口,写在里面的部分例如输出语句会被执行

func main() {

  // 在终端进行输出打印

  fmt.Println("全栈开发指南针 Let's go!")

}

有包管理情况

现在如果我们有了go mod还需要这么繁琐的去频繁get下载吗?当然不需要!

首先,我们需要在命令行终端执行一次

go mod tidy

这将自动添加代码里所有缺失的依赖并生成go.sum文件,如下图所示:

在这里插入图片描述

go.sum文件其中包含特定模块版本内容的预期加密哈希,go命令使用go.sum文件确保这些模块的未来下载检索与第一次下载相同的位,以确保项目所依赖的模块不会出现意外更改,无论是出于恶意、意外还是其他原因。 go.modgo.sum都应检入版本控制。

在这里插入图片描述

go.sum 不需要手工维护,所以可以不用太关注。

有了go.sum文件我们就可以实现代码里缺失的依赖由go mod自动下载并导入,随后我们的go mod文件里面将变成如下图所示:

在这里插入图片描述

现在同样使用上面的代码,在代码里爆红了没有关系,因为此时我们的项目里并没有使用这个引入的包做任何事。接下来我们可以将"github.com/gin-gonic/gin"从代码中删去,替换为引入另一个包"github.com/fatih/color",这是一个用于打印彩色文本的库。

// 声明main包,表明当前是一个可执行程序

package main

// 导入部分

import (

  // 导入内置的fmt包

  "fmt"

  // 导入外部包gin

  "github.com/fatih/color"

)

// main函数是程序执行的入口,写在里面的部分例如输出语句会被执行

func main() {

  // 在终端进行输出打印

  fmt.Println("全栈开发指南针 Let's go!")
  color.Red("Hello, World!")

}

直接在命令行终端运行

go run hello.go

或者用上一篇文章我们下载的Code Runner插件点击运行都可以,Go会帮我们自动下载所对应需要的依赖包,并且完成编译和执行。

结果如下:

在这里插入图片描述

Go mod常见问题解决

在使用Go mod管理包和依赖时,可能会遇到一些常见问题。这里介绍几个常见的问题以及解决方法。

  • 执行go mod tidy时出现unrecognized import path错误

这个错误通常是由于使用了未知的包导入路径,或者是没有正确配置$GOPATH环境变量所导致的。解决方法是检查导入路径,或者在执行命令之前正确配置$GOPATH环境变量。

  • 执行go mod init时出现cannot determine module path for source directory错误

这个错误通常是由于当前目录不是Go模块的根目录所导致的。解决方法是进入Go模块的根目录,再执行go mod init命令。

  • 执行go mod vendor时出现unknown flag错误

这个错误通常是由于使用了过时的go mod vendor命令所导致的。解决方法是使用新的go mod vendor命令。在Go 1.16及更高版本中,可以使用以下命令:

go mod vendor -copy = 1
  • 执行go mod download时出现no modules specified错误

这个错误通常是由于没有指定要下载的模块所导致的。解决方法是在命令后面添加要下载的模块名称,例如:

go mod download github.com/gin-gonic/gin

这个警告通常是由于存在未使用的依赖所导致的。解决方法是检查代码中是否存在未使用的依赖,如果存在,可以通过手动删除或者使用go mod edit命令来移除未使用的依赖。

小小总结📜

Go语言作为一门静态编译型语言,对于包和依赖的管理非常重要,而Go mod正是这方面的解决方案之一。Go mod能够管理依赖的版本,避免冲突问题,提高包的复用率和依赖的管理效率。与传统的依赖管理工具相比,Go mod具有优势和特点,例如本地缓存、并行下载、精确版本管理等。同时,Go mod也有一些常见的问题需要注意,例如依赖版本的选择、依赖冲突的处理等。因此,在进行Go语言模块化开发时,我们应当充分认识到Go mod的重要性,并鼓励使用它来进行包和依赖的管理。

欢迎关注公众号:“全栈开发指南针”
这里是技术潮流的风向标,也是你代码旅程的导航仪!🚀
Let’s code and have fun! 🎉

  • 14
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值