您现在的位置是:网站首页> Go语言

Go go.mod使用

摘要

重要的环境变量GOROOT也就是Go的安装目录如"c:\Go" 还有GOPATH也就是包搜索工作空间目录,默认会去搜索定义的工作空间目录下的src和go安装目录下的src

通常设置的Go工作空间比如Hello,你在工作空间创建项目HelloA,其实HelloA所在目录为Hello\src\HelloA\...

不使用.mod文件记得将.env环境文件加一行

GO111MODULE=auto获得GO111MODULE=off

在liteide中工具-》编辑当前环境


当报错没有.mod文件时候生成.mod文件

明令行:

如go Module Init  HelloJson

在开发环境里直接用菜单初始化如下

1.png

也可以

编译菜单里选择Go Module Init

golang 报错 missing go.sum entry 可以使用命令 go mod tidy 修复

go 1.13提供了 go env -w命令来写环境变量,这是用户级别的环境变量,像GO111MODULE、GOPROXY之类的可写的环境肯定是有持久化的,那么保存路径在哪儿呢?有一个env文件:

windows: 用户目录\AppData\Roaming\go\env 

linux:   /root/.config/go/env        可能是用root用户安装的,其他用户安装的可以看看 home目录下的 .config/go/env

如何使用go.mod?

1、确保go版本为1.11或更高

本文go版本号为1.16.3


2、开启gomodule

go env -w GO111MODULE=on

1

3、设置goproxy

使用国内代理提高依赖包下载速度


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



1.首先将go的版本升级为1.11以上


2.设置GO111MODULE


GO111MODULE

GO111MODULE有三个值:off, on和auto(默认值)。


GO111MODULE=off,go命令行将不会支持module功能,寻找依赖包的方式将会沿用旧版本那种通过vendor目录或者GOPATH模式来查找。

GO111MODULE=on,go命令行会使用modules,而一点也不会去GOPATH目录下查找。

GO111MODULE=auto,默认值,go命令行将会根据当前目录来决定是否启用module功能。这种情况下可以分为两种情形:

当前目录在GOPATH/src之外且该目录包含go.mod文件

当前文件在包含go.mod文件的目录下面。


go.mod 文件内提供了modulerequirereplaceexclude四个关键字

module语句指定包的名字(路径)

require语句指定的依赖项模块

replace语句可以替换依赖项模块

exclude语句可以忽略依赖项模块

indirect:表示间接依赖

indirect

indirect 总是出现在require指令中,表示这个包是被间接依赖的 // 表示注释的开始,例如:


require (

    github.com/google/uuid v1.3.0 // indirect

)

go.mod 文件中使用 indirect 关键字,告诉 Go 模块系统这个依赖项是间接的,不需要自动更新。

使用 indirect 关键字的常见场景是,当你的项目依赖于某个模块,但你只是为了传递依赖关系,而不直接使用该模块。这样可以避免不必要的模块下载和更新,减少构建过程的复杂性和时间。



1.png


Go Mod命令详解

1. init

go mod init生成mod文件


2.download

go mod download  下载 go.mod 文件中指明的所有依赖,使用此命令来下载指定的模块,模块的格式可以根据主模块依赖的形式或者path@version形式指定。


3.tidy

go mod tidy

整理现有的依赖,使用此命令来下载指定的模块,并删除已经不用的模块


4.graph

go mod graph

查看现有的依赖结构,生成项目所有依赖的报告,但可读性太差,图形化更方便。


5.edit

go mod edit

编辑 go.mod 文件,之后通过 download 或 edit 进行下载


6.vendor

go mod vendor

导出项目所有的依赖到vendor目录,从mod中拷贝到项目的vendor目录下,IDE可以识别这样的目录。


7.verify

go mod verify

校验一个模块是否被篡改过,查询某个常见的模块出错是否已被篡改


8.why

go mod why

查看为什么需要依赖某模块,查询某个不常见的模块是否是哪个模块的引用


我们将ddis指向本地包所在的目录,可以是相对路径,也可以是绝对路径

replace (

ddis => D:\GoShareLib\trunk\ddis

)

此处是不需要携带版本号的,完成上述操作之后,我们就可以直接在代码中调用本地包了


import (

"ddis"

)




在golang中,开启mod模式后,import包变红,但是程序可以正常运行

下面是我们建立了一个hello.go的文件


package main

 

import (

"fmt"

)

 

func main() {

    fmt.Println("Hello, world!")

}

当前目录下,命令行运行 go mod init + 模块名称 初始化模块


即go mod init hello


运行完之后,会在当前目录下生成一个go.mod文件,这是一个关键文件,之后的包的管理都是通过这个文件管理。


官方说明:除了go.mod之外,go命令还维护一个名为go.sum的文件,其中包含特定模块版本内容的预期加密哈希 

go命令使用go.sum文件确保这些模块的未来下载检索与第一次下载相同的位,以确保项目所依赖的模块不会出现意外更改,无论是出于恶意、意外还是其他原因。 go.mod和go.sum都应检入版本控制。 

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


注意:子目录里是不需要init的,所有的子目录里的依赖都会组织在根目录的go.mod文件里


接下来,让我们的项目依稀一下第三方包


如修改hello.go文件如下,按照过去的做法,要运行hello.go需要执行go get 命令 下载gorose包到 $GOPATH/src


package main

 

import (

"fmt"

"github.com/gohouse/gorose"

)

 

func main() {

    fmt.Println("Hello, world!")

}

但是,使用了新的包管理就不在需要这样做了


直接 go run hello.go


稍等片刻… go 会自动查找代码中的包,下载依赖包,并且把具体的依赖关系和版本写入到go.mod和go.sum文件中。

查看go.mod,它会变成这样:


module test

 

require (

github.com/gohouse/gorose v1.0.5

)

require 关键字是引用,后面是包,最后v1.11.1 是引用的版本号


这样,一个使用Go包管理方式创建项目的小例子就完成了。


问题一:依赖的包下载到哪里了?还在GOPATH/src里吗?

不在。

使用Go的包管理方式,依赖的第三方包被下载到了$GOPATH/pkg/mod路径下。

问题二: 依赖包的版本是怎么控制的?

在上一个问题里,可以看到最终下载在$GOPATH/pkg/mod 下的包中最后会有一个版本号 v1.0.5,也就是说,$GOPATH/pkg/mod里可以保存相同包的不同版本。


版本是在go.mod中指定的。如果,在go.mod中没有指定,go命令会自动下载代码中的依赖的最新版本,本例就是自动下载最新的版本。如果,在go.mod用require语句指定包和版本 ,go命令会根据指定的路径和版本下载包,

指定版本时可以用latest,这样它会自动下载指定包的最新版本;


问题三: 可以把项目放在$GOPATH/src下吗?

可以。但是go会根据GO111MODULE的值而采取不同的处理方式,默认情况下,GO111MODULE=auto 自动模式


1.auto 自动模式下,项目在$GOPATH/src里会使用$GOPATH/src的依赖包,在$GOPATH/src外,就使用go.mod 里 require的包


2.on 开启模式,1.12后,无论在$GOPATH/src里还是在外面,都会使用go.mod 里 require的包


3.off 关闭模式,就是老规矩。


问题三: 依赖包中的地址失效了怎么办?比如 golang.org/x/… 下的包都无法下载怎么办?

在go快速发展的过程中,有一些依赖包地址变更了。以前的做法:


1.修改源码,用新路径替换import的地址


2.git clone 或 go get 新包后,copy到$GOPATH/src里旧的路径下


无论什么方法,都不便于维护,特别是多人协同开发时。


使用go.mod就简单了,在go.mod文件里用 replace 替换包,例如


replace golang.org/x/text => github.com/golang/text latest


这样,go会用 github.com/golang/text 替代golang.org/x/text,原理就是下载github.com/golang/text 的最新版本到 $GOPATH/pkg/mod/golang.org/x/text下。

问题四: init生成的go.mod的模块名称有什么用?

本例里,用 go mod init hello 生成的go.mod文件里的第一行会申明module hello


因为我们的项目已经不在$GOPATH/src里了,那么引用自己怎么办?就用模块名+路径。


例如,在项目下新建目录 utils,创建一个tools.go文件:


package utils

 

import “fmt”

 

func PrintText(text string) {

    fmt.Println(text)

}

在根目录下的hello.go文件就可以 import “hello/utils” 引用utils


package main

 

import (

"hello/utils"

"github.com/astaxie/beego"

)

 

func main() {

utils.PrintText("Hi")

beego.Run()

}

问题五:以前老项目如何用新的包管理

如果用auto模式,把项目移动到$GOPATH/src外

进入目录,运行 go mod init + 模块名称

go build 或者 go run 一次





按原来方式创建好项目,然后初始化出.mod文件也就是执行命令行 Go Module Init 主文件名 

如go Module Init  HelloJson

在开发环境里直接用菜单初始化如下

1.png

生成文件go.mod文件如下


module github.com/xuneng/hellojson  /*这个表示目前项目包是github.com/xuneng/hellojson,不是直接到Go目录下去找该包的文件,是在本项目目录下查找,发布之后是github.com/xuneng/hellojson*/

go 1.13


require (

github.com/auth0/go-jwt-middleware v0.0.0-20190805220309-36081240882b

github.com/dgrijalva/jwt-go v3.2.0+incompatible

github.com/go-redis/redis/v7 v7.2.0

github.com/gorilla/mux v1.7.4 // indirect

github.com/kr/pretty v0.1.0

github.com/patrickmn/go-cache v2.1.0+incompatible

github.com/satori/go.uuid v1.2.0

github.com/sirupsen/logrus v1.5.0

github.com/spf13/pflag v1.0.3

github.com/spf13/viper v1.6.3

github.com/stretchr/testify v1.4.0

github.com/urfave/negroni v1.0.0 // indirect

)


正式的livego的mod文件:

module github.com/gwuhaolin/livego


go 1.13


require (

github.com/auth0/go-jwt-middleware v0.0.0-20190805220309-36081240882b

github.com/dgrijalva/jwt-go v3.2.0+incompatible

github.com/go-redis/redis/v7 v7.2.0

github.com/gorilla/mux v1.7.4 // indirect

github.com/kr/pretty v0.1.0

github.com/patrickmn/go-cache v2.1.0+incompatible

github.com/satori/go.uuid v1.2.0

github.com/sirupsen/logrus v1.5.0

github.com/spf13/pflag v1.0.3

github.com/spf13/viper v1.6.3

github.com/stretchr/testify v1.4.0

github.com/urfave/negroni v1.0.0 // indirect

)


在 Go 语言的模块(module)文件(go.mod)中,+incompatible 是一个特殊的修饰符,用于处理与兼容性相关的模块版本问题。它通常在模块的版本号后面使用,用于指示该版本与先前版本不兼容。

在 Go 模块系统中,每个模块都有一个唯一的版本号,以便其他模块可以明确地依赖于该版本。当一个模块的 API 发生重大变化,不再与先前版本兼容时,开发人员可以选择在模块版本号后面添加 +incompatible 标记来表示这种不兼容性。

使用 +incompatible 的目的是为了与旧版本的模块保持向后兼容。当你需要升级一个模块,并且新版本与先前版本不兼容时,可以使用 +incompatible 标记来指示模块管理工具(如 Go Modules)在解析依赖关系时允许使用不兼容的版本。

使用方法如下:

在你的 go.mod 文件中,将模块的版本号后面添加 +incompatible 标记,例如:


module example.com/myapp/v2


go 1.16


require (

    example.com/mymodule v2.0.0+incompatible

)

在引入该模块时,使用带有 +incompatible 标记的版本号,例如:


import (

    "example.com/mymodule/v2"

)

需要注意的是,+incompatible 标记是一种权宜之计,应该尽量避免使用。它适用于那些真正需要破坏向后兼容性的情况,例如重构或重大架构更改。在大多数情况下,应该尽量保持模块的向后兼容性,并使用合适的语义版本控制来管理模块的演进。











Top