详解go语言包管理方式(go mod), 分析多目录多文件下的管理,不同工程下包的相互调用

news2024/12/30 2:58:36

先明白一个点, 想要成功运行一个go程序, 有两种模式
一: 以前的默认模式,必须将项目放在gopath/src下
二:使用go mod 包管理方式, 项目可以放到任意位置,这样目录下需要有go.mod文件

下边我会分析 :
1.GO111MODULE 的三种模式,
2.将项目放在gopath/src下, 但却使用go.mod 包管理的方式
3.多文件,多目录下,go mod 包管理的使用细节

通过go env 命令 可以看到 GO111MODULE 字段
可以通过export GO111MODULE=’ ’ 来修改,当然这种命令的方式是在linux下, 若是windows平台,直接去设置环境变量即可

它有三种状态:

auto
如果在gopath/src下,但是存在go.mod文件,就采用的go mod包管理方式;
若没有go.mod文件, 采用以前默认的方式(项目必须放在gopath/src下);
若未在gopath/src下, 自然是采用的go mod包管理方式(前提是需要go.mod文件存在)

on, 不管在不在gopath/src下,都采用的go mod包管理方式

off,就是以前的默认方式(项目必须放在gopath/src下),若需要引用外部包文件,使用go get命令下载下来。
比如在一个.go文件中,require (“github.com/gin-gonic/gin”)
那么使用go get github.com/gin-gonic/gin ,并且这个下载下来的资源会放在gopath/src下, 而使用go mod包管理的方式,下载下来的资源会放在gopath/pkg下,后边会用测试案例详细介绍如何操作。

小细节:
采用go mod 包管理方式, 虽然不会去gopath/src下找资源, 但是会去gopath/pkg下找资源, 同时还会去goroot/src下寻找(回忆一下, 最常用的fmt.Println(), fmt等等那些包就在那里);
采用以前的默认方式, 就会去gopath/src, 以及goroot/src下寻找,不管是哪种方式都需要去goroot/src,因为fmt等包是在安装go的时候就下载好的资源。

实例演示:

先用go env 查看go的环境变量,重点记住gopath路径
在这里插入图片描述
1:先展示以前的默认方式,
使用export GO111MODULE=“off”, 表示关闭go mod包管理方式,采用默认的模式,那么我们的工程就必须放在gopath/src下。
我的gopath/src 是/home/jt/go
为了更好的演示为什么以前默认的方式必须在gopath/src下, 这里(/home/jt/go)我们再创建一个文件夹
mkdir my_gotest2
cd my_gotest2
touch main.go
mkdir -p pkg/util
cd pkg/util
vim test.go , 内容如下

package util
import("fmt")
func Test() {	//注意首字母大写, 不然无法调用,大写表示允许被调用
        fmt.Println("I'm pkg/util/Test()")
}  

现在我们需要在main.go 中调用这个Test() 函数
main.go 内容 , go run main.go 即可看到结果

package main
import("my_gotest2/pkg/util")
func main() {
        util.Test()
}

这里主要分析import(“my_gotest2/pkg/util”) , 对于以前的默认方式,也就是项目必须放到gopath/src下的原因, 其实它会在my_gotest2/pkg/util前面自动加上gopath/src路径(我的是/home/jt/go), 完整的写出来其实是/home/jt/go/my_gotest2/pkg/util, 这也就是为什么必须放到gopath/src下。

2.现在我们采用go mod包管理的方式
现在的项目路径在gopath/src下(即/home/jt/go)
使用go mod init demo 生成 一个go.mod 文件 (demo名字是自己取的,什么都是可以,记住它)
使用export GO111MODULE=“auto” , 这里为什么使用auto而不使用on,因为想给大家分析在gopath/src下却使用auto模式,它会使用go mod包管理方式,还是采用以前的默认方式? 答案是如果存在go.mod文件就会用go mod包管理方式, 如果没有go.mod 就使用以前默认方法,当然前提是放在gopath/src路径下。

这种情况下我们如何才能在main.go中调用pkg/util下的Test()函数呢?
直接go run main.go

main.go:3:8: package my_gotest2/pkg/util is not in GOROOT (/usr/lib/go-1.18/src/my_gotest2/pkg/util)

可以看到以上报错, 其实很细节,为什么没去gopath/src下找呢, 因为我们此时是go mod包管理方式,那么又为什么要去GOROOT(goroot/src)下找呢? 因为像fmt那些包都在那,所以不管是否开启go mod包管理模式都会去goroot/src找。

正确的方式是将刚才的import(“my_gotest2/pkg/util”) 换成 import(“demo/pkg/util”)
这个demo是我们上边go mod init demo 生成的项目模块名称,可以在go.mod中看到。
再次go run main.go 即可成功
注意到我们最开始使用的go mod init demo 的重要性没有, demo用来替代了当下的绝对路径,在这里其实demo表示的是/home/jt/go/my_gotest2, 所以它并不依赖gopath/src(/home/jt/go), 你将项目移到其他位置, demo就会表示那个位置的绝对路径, demo可以换成任意字符, 比如你最开始用的是go mod init demo_test, 那么这里就要 import(“demo_test/pkg/util”), 可以在go.mod文件中对它进行修改。

以上就是默认方式 以及 go mod包管理方式的简单使用

拓展1:go mod包管理方式,如何调用不同工程中的包
以上的文件都是在同一个工程下,接下来我们创建两个工程, 我直接给出方法,以及如何写代码,建议自行放到电脑上运行查看加深理解

在任意位置创建 两个文件夹
我当前的工作路径是/home/jt
mkdir my_gotest my_gotest2
目标是在my_gotest2工程中调用my_gotest中的util包,使用SayHello函数
cd my_gotest
mkdir -p pkg/util
vim hello.go

package util
import("fmt")
func SayHello() {
        fmt.Println("hello -- from my_gotest")
}

回到my_gotest目录
go mod init github.com/cnwyt/my_gotest //这里为什么这样命名,方便你后续可以把包提交到github上供他人调用。
就像我们上边说的go mod init 后边的名字是自己取的
这里的github.com/cnwyt/my_gotest就代表的是my_gotest文件夹的绝对路径
相当于 /home/jt/my_gotest

现在我们去到my_gotest2文件夹
go mod init my_gotest2
现在我们要调用my_gotest中的util包
touch main.go (my_gotest2目录 下)

package main
import(
        "fmt"
		"github.com/cnwyt/my_gotest/pkg/util"
)
func main() {
        fmt.Println("Hello, my_gotest2")
        util.SayHello();
} 

显然 github.com/cnwyt/my_gotest/pkg/util 并不是github官网上的,而是我们本地的,所以我们需要在go.mod((/home/jt/my_gotest2))中修改一下

module my_gotest2
go 1.18
require github.com/cnwyt/my_gotest v0.0.0
replace github.com/cnwyt/my_gotest => /home/jt/my_gotest  //这就是replace的用处,用于替换

replace不仅可以这样做,比如你在以前在github上引用的包,但时间长了,可能作者改变了它的位置。
举例:
replace github.com/gin-gonic/gin v1.0.1 => github.com/piannide/gin v1.0.2 //当然版本号只是举例,不一定是这个版本
其实它的意思就是, 去把新位置(github.com/piannide/gin)的包下载下来放到了老位置(gopath/pkg/github/gin-gonic)下,这样就可以继续使用了,而不用做太大改动

回到我们的目标
此时我们 go run main.go 就可以发现成功调用了

这里还有一个小细节,比如包的名字重复了:
在my_gotest2下
mkdir pkg/util
vim datetime.go

package util
import("time")
func UnixTime() int64 {
        return time.Now().Unix()
}

此时这个包名还是util, 刚才我们引用的my_gotest中的包也是util,那么怎么区别呢?
去看看my_gotest2中go.mod的内容
可以看到我们的项目名为my_gotest ,将main.go的内容更改如下 ,即可解决包名冲突问题

package main
import(
        "fmt"
        "my_gotest2/pkg/util"   
        //因为是go mod包管理方式,其实my_gotest2就相当于替换了当前工程的绝对路径(/home/jt/my_gotest2)
        util2"github.com/cnwyt/my_gotest/pkg/util"
)
func main() {
        fmt.Println("Hello, my_gotest2")
        t := util.UnixTime()
        fmt.Println("timestap:", t)
        util2.SayHello();
}

以上内容都是对于本地包的引用, 那么如果想引用github上的包怎么操作?
我们以github.com/gin-gonic/gin 为例子
我们在main.go 中 (任意地方),当然因为是go mod包管理方式, 必须先通过go mod init ”任意” 生成go.mod 文件,把main.go 写好后, 使用 go mod tidy 它会自动去查找工程下所有.go文件引用的外部资源,并自动下载下来, 下载下来后可以去 gopath/pkg/mod/github.com/ 中看到 gin-gonic
对比以前的默认方式, 以前是使用 go get github.com/gin-gonic/gin, 然后这个资源会下载到gopath/src中, 当然go mod包管理方式也是可以使用go get命令的。
此时就可以正常go run main.go 运行文件了

package main
import (
  "net/http"
  "github.com/gin-gonic/gin"
)
func main() {
  r := gin.Default()
  r.GET("/ping", func(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{
      "message": "pong",
    })
  })
  r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}

拓展2
go mod的方式如何在多文件中应用
比如工程结构如下。

├── calc
│   └── calc.go
├── go.mod
├── main.go
├── main_son.go
└── pkg
    └── util
        ├── t1.go
        ├── t2.go
        └── t3.go

我们的目标是:

  1. 如何在calc.go中调用pkg/util中的包函数。
  2. main包实现的功能如何拆分在不同文件中。
    这里我们又会学习到一个新的小知识,比如这里的t1.go ,t2.go和 t3.go
    只要包名一样(main包有点区别,后边说),他们的功能实现可以在不同文件中。

这个go.mod 是通过go mod init demo 生成的

cala.go

package calc
import(
        "demo/pkg/util"	//主要就是学习它怎么写
        "fmt"
)
func Add(x, y int) int {
        fmt.Println("我是calc, 我在这里调用了Say3()")
        util.Say3()
        return x + y
}

t1.go, t2.go, t3.go 内容

package util
t1.go 
import("fmt")
func Say1() {
        fmt.Println("I'm t1")
}

t2.go
package util
import("fmt")
func Say2() {
        fmt.Println("I'm t2")
}

t3.go
package util
import("fmt")
func Say3() {
        fmt.Println("I'm t3, I will user t1 and t2!!")
        Say1()
        Say2()
}

至此第一个目标实现

由上可见,对于普通包,这里是util包, 可以直接引用同包名下其他文件的函数,而main包有点区别
main. go 和 main_son.go 都数据main包, 我们去看一下他们的实现

package main
import(
        "fmt"
        "demo/pkg/util"
        "demo/calc"
)
func main() {
        fmt.Println("test_ main")
        fmt.Println("--------------")
        util.Say1()
        fmt.Println("---------------")
        util.Say2()
        fmt.Println("-------------")
        util.Say3()
        fmt.Println("--------------")
        sum := calc.Add(1, 2)
        fmt.Println(sum)
        
        fmt.Println("---------------")
        //test()  
}

可以看到我把test()注释了,因为他是在main_son.go中实现的,在这种情况下我们使用
go run main.go 程序是可以正常执行的, 但当你打开注释,会提示

//使用 go run main.go
# command-line-arguments
./main.go:23:2: undefined: test

此刻的正确方式是将main_son.go 放到命令行参数中,如
go run main.go main_son.go //此刻即可正常执行

go build 又是什么?

主要用于编译代码,输出可执行文件,比如将源码打包成可执行文件部署线上服务
//如果是普通包(非main包), 只做检查, 不产生可执行文件
//如果是main包,生成可执行文件, 默认生成的可执行文件名为项目名(go mod里面)

//命令: go build main.go

// -o 参数指定可执行文件名称

//交叉编译
在linux生成window需要的   exe文件
GOOS=windows GOARCH=amd64 go build  -o demo.exe mian.go
反之
GOOS=linux GOARCH=amd64 go build  -o demo mian.go

如遇任何问题欢迎评论区留言~!!

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

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

相关文章

毕业设计 stm32单片机的目标检测与跟踪系统 -物联网 openmv 嵌入式

文章目录0 前言课题简介设计框架3 硬件设计4 软件设计对被测物体的识别判断被测物体所在区域5 最后0 前言 🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年…

力扣(LeetCode)1812. 判断国际象棋棋盘中一个格子的颜色(C++)

数学 如果我们把国际象棋的横轴看做从 111 到 888 ,那么每个棋子的坐标形如 a1(1,1)a1(1,1)a1(1,1) c4(3,4)c4(3,4)c4(3,4) ,想想坐标之和有没有什么规律。 规律 : 黑子坐标之和为偶数,白子坐标之和为奇数。 横轴坐标是我们自定义的&#x…

基于蚁群算法的三维路径规划算法以及蚁群算法的优化计算——TSP优化(Matlab代码实现)

目录 1 概述 1.1简介 1.2 改进的蚁群算法 2 部分运行结果 2.1 三维路径规划算法 2.2 TSP优化算法 3 Matlab代码实现 4 参考文献 1 概述 1.1简介 当前社会, 很多用户需要在复杂的没有公路的山地地形, 快速、准确的规划出三维路径, 在避过障碍的同时达到某项指标最优。…

【C++笔试强训】第四天

文章目录选择题编程题选择题 #include<iostream> #include<cstdio> using namespace std; int main(){int m0123, n123;printf("%o %o\n", m, n);return 0; }程序运行后的输出结果是&#xff08;&#xff09; A 0123 0173 B 0123 173 C 123 173 D 173 1…

RabbitMQ基本使用

先会用&#xff0c;知道mq是干嘛的&#xff0c;怎么用RabbitMQ 再去考虑一系列深入东西 一&#xff1a;什么是MQ MQ消息队列详解、四大MQ的优缺点分析_从百草园杀到三味书屋&的博客-CSDN博客 理解什么是MQ MQ在企业/程序中的作用是什么&#xff1f; MQ&#xff0c;中文是…

Fluent的porous jump边界条件

1 porous jump简介 多孔介质指内部具有连通的空洞&#xff0c;可使流体穿过的固体。多孔介质具有以下特点&#xff1a; 流道极复杂&#xff0c;活性炭过滤器等随机排布的多孔介质甚至不存在可通过曲面和实体表征的确定流道多孔介质只是流场的一部分&#xff0c;通常不关注多孔…

DataSphere Studio数据应用开发管理集成框架【DSS基础】

https://github.com/WeBankFinTech/DataSphereStudio/https://gitee.com/WeBank/DataSphereStudio 基于插拔式的集成框架设计&#xff0c;及计算中间件 Linkis &#xff0c;可轻松接入上层各种数据应用系统&#xff0c;让数据开发变得简洁又易用。在统一的 UI 下&#xff0c;Da…

[附源码]Python计算机毕业设计Django中小学课后延时服务管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

前端_Vue_2.创建一个Vue应用、模板语法

文章目录一、创建一个Vue应用1.1. 应用实例1.2. 根组件1.3. 挂载应用1.3.1. DOM中的根组件模板1.4. 应用配置1.5. 多个应用实例二、模板语法2.1. 文本插值2.2. 原始HTML2.3. Attribute绑定2.3.1. 简写2.3.2. 布尔型 Attribute2.3.3. 动态绑定多个值2.4. 使用JavaScript表达式2.…

记录一次Sql性能优化

场景&#xff1a; 主业务表 contract&#xff08;合同表&#xff09;&#xff0c;对于不同主体&#xff08;人员&#xff09;&#xff0c;能查看的合同是不一样的。系统企业业务用到了&#xff0c;系统资源表 PERMISSION_RESOURCE 、员工对于资源关系表&#xff1a;ENTRY_JOIN…

物联卡批发为什么那么火爆?

2022年物联网行业开始爆发&#xff0c;针对于企业设备联网的物联卡就显得格外重要了&#xff0c;而共享单车&#xff0c;移动支付&#xff0c;智慧城市&#xff0c;自动售卖机等企业采购物联卡会面临着各种问题&#xff0c;低价陷阱&#xff0c;流量虚假&#xff0c;管理混乱&a…

[Python图像处理] 合成微缩效果

合成微缩效果前言图像微缩效果原理实现图像微缩效果相关链接前言 图像中的模糊效果可以强烈影响被拍摄场景的感知&#xff0c;模糊在传达所需的尺寸和距离感方面起着重要作用。合成微缩 (miniature faking) 是一个使真实大小物体照片看起来像微缩模型照片的过程&#xff0c;也…

java必背综合知识点总结

一、JDK常用的包 java.lang&#xff1a; 这个是系统的基础类&#xff0c;比如String、Math、Integer、System和Thread&#xff0c;提供常用功能。 java.io: 这里面是所有输入输出有关的类&#xff0c;比如文件操作等 java.net: 这里面是与网络有关的类&#xff0c;比如URL,U…

寻找适配网红很迷茫?最全秘笈来了

根据《2022年全球数字概览》报告显示&#xff0c;全球社交媒体用户超过46.2亿&#xff0c;相当于全球总人口的58.4%。全球用户每天在社交媒体上平均花费近2.5个小时&#xff0c;并且每天以2分钟的速度增长。 社交媒体成为全球网民生活中不可或缺的一部分&#xff0c;而对于跨境…

【深度学习】Yolov5训练意外中断后如何接续训练详解;yolov5中断后继续训练

0. 前言 目标检测是计算机视觉上的一个重要任务,下面这篇文章主要给大家介绍了关于Yolov5训练意外中断后如何接续训练的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下 1. 配置环境 操作系统&#xff1a;Ubuntu20.04 CUDA版本&#xff1a;11.4 Pytorch版本…

Excel - 数据分析师所需的最常用公式。

“先打好基础,再细化细节——克里斯安德森” 这将是我正在撰写的关于必须具备数据分析技能的第 4 个也是最后一个“像你 5 岁一样解释”系列。(请观看其他的——Power BI、Python 和 SQL)。现在,我们将具备所需的所有基本技能,然后可以进入数据分析领域的下一阶段 使用 E…

Java实现大乐透不重复数字随机号码生成方案

大乐透攻略Java实现&#xff08;仅供参考学习&#xff09; 购票方式 每期最低购票数&#xff1a;7 张 最低消费&#xff1a;14 元 方案介绍&#xff1a;后区12个数中随机分成6组&#xff0c;且数字不重复。前区35个数随机分成7组&#xff0c;且数字不重复。前区需要7组才能够…

【目标检测】IoU、GIoU、DIoU、CIoU、EIoU 5大评价指标

目录 一、简介 二、IoU&#xff08;Intersection over Union&#xff09; 三、GIoU&#xff08;Generalized IoU&#xff09; 四、DIoU&#xff08;Distance-IoU&#xff09; 五、CIoU(Complete-IoU) 六、EIoU(Efficient-IoU) 七、pytorch代码实现 七、总结 一、简介 在目标检测…

即时通讯开发之如何测试实时语音通话质量

实时语音聊天开发&#xff0c;对于一般的开发者来说比较神秘&#xff0c;很多朋友不太清楚如何全面的评估一个音频引擎。很多朋友还停留在这样的初级阶段&#xff1a;把demo调通&#xff0c;找几个人喂喂喂......凭自己优异的听觉感受一下&#xff0c;整个测试过程就完成了。 但…

【嵌入式硬件芯片开发笔记】EEPROM芯片M24C32配置流程

【嵌入式硬件芯片开发笔记】EEPROM芯片M24C32配置流程 32-Kbit serial IC bus EEPROM - 105C operation 适用于M24C32/M24C32-DRE 读取存储的从机地址为&#xff1a;0x50 读取标识页面的从机地址为&#xff1a;0x58 WC引脚接地&#xff0c;存储可以进行写操作 地址长度为16位 存…