壹 包的介绍
Go
语言是支持模块化的开发理念的,在Go
语言项目开发中使用包(package)
来支持代码模块化和代码复用。一个包是由一个或多个Go
源码文件(.go
结尾的文件)组成,是一种高级的代码复用方案,Go
语言为我们提供了很多内置包,如fmt
、os
、io
等。
贰 包的定义
我们可以根据自己的需要创建自定义包。一个包可以简单理解为一个存放.go
文件的文件夹,该文件夹下面的所有.go
文件都要在非注释的第一行添加如下声明,声明该文件归属的哪个包。
package 自定义包的名字
// package:声明包的关键字
// packagename:包名,可以不与文件夹的名称一致,但是不能包含 - 符号,所有的包名都应该使用小写字母,最好与其实现的功能相对应。
注意:一个文件夹下存放的所有.go
文件只能归属一个包,归属在同一个包的.go
文件不能存放在多个文件夹下。包名为main
的包是Go
语言的应用程序的入口包,这种包编译后会得到一个可执行文件,而编译不包含main
包的源代码则不会得到可执行文件,而是。
叁 标识符可见性
在同一个包内部声明的标识符都归属与同一个命名空间,而在不同的包内部声明的标识符就属于各自的命名空间。想要在包的外部使用包内部的标识符就需要添加包名前缀,例如fmt.Println("Hello world!")
,就是指调用fmt
包中的Println
函数。
如果想让一个包中的标识符(如变量、常量、类型、函数等)能被外部的包使用,那么标识符必须是对外可见的,这就像Java
的权限修饰符(public)
公共权限一样。而在Go
语言中是通过标识符的首字母大/
小写来控制标识符的对外可见(public)
/不可见(private)
的。在一个包内部只有首字母大写的标识符才是对外可见的,才能被外部使用。
package pkg2
import "fmt"
// 包变量可见性
var a = 100 // 首字母小写,外部包不可见,只能在当前包内使用
// 首字母大写外部包可见,可在其他包中使用
const Mode = 1
type person struct { // 首字母小写,外部包不可见,只能在当前包内使用
name string
}
// 首字母大写,外部包可见,可在其他包中使用
func Add(x, y int) int {
return x + y
}
func age() { // 首字母小写,外部包不可见,只能在当前包内使用
var Age = 18 // 函数局部变量无论开头是大小写,由于只在当前函数内部的作用域,外部包不可见,只能在当前函数内使用
fmt.Println(Age)
}
结构体中的字段名和接口中的方法名如果首字母都是大写,外部包可以访问这些字段和方法。
type Student struct {
Name string // 可在包外访问的方法
class string // 仅限包内访问的字段
}
type Payer interface {
init() //仅限包内访问的方法
Pay() //可在包外访问的方法
}
肆 包的引用
当我们需要在当前包中使用另外一个包的内容时,就需要使用import
关键字引入这个包,并且import
语句通常放在package
声明语句的下方。完整的引入声明语句格式如下:
import importname "path/to/package"
// importname:为引入包取的别名,通常都省略,省略的话,默认值为引入包的包名
// path/to/package:引入包的路径名称,包名是从$GOPATH/src/后开始计算的,,使用/进行路径分隔,必须使用双引号包裹起来
// Go语言中禁止循环导入包
引入包可以使用如下格式:
import "包1"
import "包2"
也可以批量引用:
import (
"包1"
"包2"
)
当引入的多个包中存在相同的包名或者想为某个引入的包设置一个新包名时,都需要通过importname
指定一个在当前文件中使用的新包名。例如,在引入fmt
包时为其指定一个新包名f
。
import f "fmt"
或者批量:
import (
f "fmt"
o "os"
)
使用包里面的函数就可以通过别名进行调用:
f.Println("Hello world!")
如果引入一个包的时候为其设置了一个特殊_
作为别名,那么这个包的引入方式就称为匿名引入。一个包被匿名引入的目的主要是为了加载这个包,从而使得这个包中的资源得以初始化。 被匿名引入的包中的init
函数(这个函数下面会仔细讲解)将被执行并且仅执行一遍。
// 该包是引用mysql数据库包,需要进行初始化
import _ "github.com/go-sql-driver/mysql"
匿名引入的包与其他方式导入的包一样都会被编译到可执行文件中。需要注意的是,Go
语言中不允许引入包却不在代码中使用这个包的内容,如果引入了未使用的包则会触发编译错误,但是使用_
设置别名,导入的包是已经加载使用的了,不会报错!
还有一种使用点的操作:
import(
. "fmt"
)
这个点操作的含义就是这个包导入之后在你调用这个包的函数时,你可以省略前缀的包名,也就是前面你调用的:
fmt.Println( "hello go" )
可以写成:
Println( "hello go" )
伍 init初始化函数
Go
语言有一个特殊的函数init
,会在每个包完成初始化后自动执行,并且执行的优先级比main
函数高,实现包级别的一些初始化操作!该函数默认没有执行代码,需要用户自定义初始化!init
函数有一下特性:
init
函数是程序执行前对包进行初始化的函数- 每个包可以有多个
init
函数,并且是以顺序方式执行 - 包的每个源文件也可以有多个
init
函数 - 同一个包中多个
init
函数的执行顺序是顺序执行 - 不同包的
init
函数按照包导入的依赖关系决定该初始化函数的执行顺序 init
函数不能被其他函数调用,而是在main
函数执行之前,自动被调用,如果被其他函数调用会出现undefined:init
错误init
函数没有参数也没有返回值
init
函数的主要作用:
- 初始化不能采用初始化表达式的初始化变量
- 需要在
main
函数运行前的执行的代码,就是对包的初始化 - 实现
sync.Once
功能(后面的并发会讲解该功能)
对于单个包的初始化,总是以单线程执行,初始化的顺序是全局声明 =>
init
函数 =>
main
函数:
package main
// 1.初始化全局声明
var value int
func init() {
// 2.初始化init函数内的语句
print("开始初始化变量value!\n")
value = 1
}
func main() {
// 3.运行main函数内的语句
print("初始化后的变量value:", value)
}
上面是没有引入其他包的情况下,对于引入其他包,应用程序的初始化是最前面的包初始化(进入其他包还是按照单个包初始化顺序进行) =>
全局声明 =>
init
函数 =>
main
函数:
像前面一样,如果只需要一个包的init
初始化函数,不需要这个包的其他方法,可以使用匿名引入,这样就表示只执行这个包的init
函数。
import _ "github.com/go-sql-driver/mysql"
这里需要注意无论包被导入多少次,初始化只需要一次。这样的好处是开发者如果引用第三方库的时候,本地的库引用了与第三方库的引用的库重复,就不会多次初始化库,这也使得Go
语言允许开发者对外发布包或者库,也支持开发者在自己的代码中引入第三方库。
陆 Go包的依赖管理介绍
最早的时候,Go
所依赖的所有的第三方库都放在GOPATH
这个目录下面。这就导致了同一个库只能保存一个版本的代码。如果不同的项目依赖同一个第三方的库的不同版本,就成为了Go
语言一个致命的缺陷。
首先我们看看Go
官方对依赖管理的小历史:
- 2012年3月
Go 1
发布,此时没有版本的概念 - 2013年
Golang
团队在FAQ
中提议开发者保证相同import path
的兼容性,后来成为一纸空文 - 2013年10月出现
Godep
- 2014年7月出现
glide
- 2014年有人提出
external packages
的概念,在项目的目录下增加一个vendor
目录来存放外部的包 - 2015年8月
Go 1.5
实验性质加入vendor
机制 - 2015年有人提出了采用语义化版本的草案
- 2016年2月
Go 1.6
vendor
机制 默认开启 - 2016年5月
Go
团队的Peter Bourgon
建立委员会,讨论依赖管理工具,也就是后面的dep
- 2016年8月
Go 1.7
vendor
目录永远启用 - 2017年1月
Go
团队发布Dep
,作为准官方试验 - 2018年8月
Go 1.11
发布Modules
作为官方试验 - 2019年2月
Go 1.13
发布Modules
将是Go
语言默认的依赖管理工具 - 2019年9月
Go 1.16
版本默认开启Modules
模式
根据小历史,我们可以看出GO
依赖管理分三个阶段:GOPATH
、GOVENDOR
、go module
,所以Go
官方为了解决这个问题,Go
在v1.5
发布之后,首先引入了vender
路径查找的解决方案。
vender
路径被添加到除了GOROOT
和GOPATH
之外的依赖目录,查找依赖包路径的的顺序如下:
- 当前包的
vender
目录 - 向上级目录查找,直到找到
src
下的vender
目录 - 在
GOPATH
下查找依赖包 - 在
GOROOT
目录下查找依赖包
后来Go
官方继续优化依赖管理,后来在 Go1.11
提出了 Modules
。由于vender
依赖模式比较老旧,所以我们这里主要讲的Go包的依赖管理是Modules
。如果对vender
模式感兴趣的兄弟可以自行谷歌查找对应的使用!推荐阅读官方文档:传送门1、传送门2、传送门3。
柒 go module介绍
Go module
是 Go1.11
版本发布的依赖管理方案,于Go1.16
版本默认开启。
7.1 GO111MODULE
Go
语言在 go module
的过渡阶段提供了 GO111MODULE
这个环境变量来作为是否启用 go module
功能的开关。其实在 Go1.16
之后 go module
已经默认开启,这里只是简单了解即可!
要启用go module
支持首先要设置环境变量GO111MODULE
,通过它可以开启或关闭模块支持,它有三个可选值:off
、on
、auto
,默认值是auto
。
GO111MODULE=off
:禁用模块支持,编译时会从GOPATH
和vendor
文件夹中查找包GO111MODULE=on
:启用模块支持,编译时会忽略GOPATH
和vendor
文件夹,只根据go.mod
下载依赖GO111MODULE=auto
:当项目在$GOPATH/src
外且项目根目录有go.mod
文件时,开启模块支持
设置GO111MODULE=on
之后就可以使用go module
了,以后就没有必要在GOPATH
中创建项目了,并且还能够很好的管理项目依赖的第三方包信息。使用 go module
管理依赖后会在项目根目录下生成两个文件go.mod
和go.sum
。
7.2 GOPROXY
这个环境变量主要是用于设置 Go
模块代理,其作用是用于使 Go
在后续拉取模块版本时能够脱离传统的 VCS
方式,直接通过镜像站点来快速拉取。
Go1.13之后 GOPROXY
的默认值是:https://proxy.golang.org,direct
,由于某些原因国内无法正常访问该地址,所以我们通常需要配置一个可访问的地址。目前社区使用比较多的有两个https://goproxy.cn
和https://goproxy.io
,当然如果有私有的GOPROXY
地址那么就直接使用。设置GOPAROXY
的命令如下:
go env -w GOPROXY=https://goproxy.cn,direct
GOPROXY
允许设置多个代理地址,多个地址之间需使用英文逗号 ,
分隔。最后的 direct
是一个特殊指示符,用于指示 Go
回源到源地址去抓取(比如 GitHub
等)。当配置有多个代理地址时,如果第一个代理地址返回 404
或 410
错误时,Go
会自动尝试下一个代理地址,当遇见 direct
时触发回源,也就是回到源地址去抓取。
7.3 GOPRIVATE
设置了 GOPROXY
之后,Go
命令就会从配置的代理地址拉取和校验依赖包。当我们在项目中引入了非公开的包(内部git
仓库或 github
私有仓库等),此时便无法正常从代理拉取到这些非公开的依赖包,这个时候就需要配置 GOPRIVATE
环境变量。GOPRIVATE
用来告诉 Go
命令哪些仓库属于私有仓库,不必通过代理服务器拉取和校验。
GOPRIVATE
的值也可以设置多个,多个地址之间使用英文逗号 ,
分隔。我们通常会把自己公司内部的代码仓库设置到 GOPRIVATE
中,例如:
$ go env -w GOPRIVATE="git.mycompany.com"
这样在拉取以git.mycompany.com
为路径前缀的依赖包时就能正常拉取了。此外,如果公司内部自建了 GOPROXY
服务,那么我们可以通过设置 GONOPROXY=none
,允许通内部代理拉取私有仓库的包。一般情况下,我们都会设置 GONOPROXY=none
。
7.4 go mod命令
对于 Go module
的使用,官方提供了以下命令:
命令 | 介绍 |
---|---|
go mod init |
初始化项目依赖,生成go.mod 文件 |
go mod download |
根据go.mod 文件下载依赖(默认为$GOPATH/pkg/mod 目录) |
go mod tidy |
比对项目文件中引入的依赖与go.mod 进行比对 |
go mod graph |
输出依赖关系图 |
go mod edit |
编辑go.mod 文件 |
go mod vendor |
将项目的所有依赖导出至vendor 目录下 |
go mod verify |
检验一个依赖包是否被篡改过 |
go mod why |
解释为什么需要某个依赖 |
捌 使用go module引入包
8.1 初始化项目
如何使用 go module
拉取和管理项目依赖呢?首先需要我们初始化项目,在本地创建一个名为demo
的文件夹并切换到该目录下,然后执行下面命令初始化项目:
PS C:\Desktop\demo> go mod init demo
go: creating new go.mod: module demo
该命令会自动在项目目录下创建一个go.mod
文件,其内容如下:
// 定义当前项目的导入路径
module demo
// 标识当前项目使用的 Go 版本
go 1.18
go.mod
文件会记录项目使用的第三方依赖包信息,包括包名和版本,由于我们的demo
项目目前还没有使用到第三方依赖包,所以go.mod
文件暂时还没有记录任何依赖包信息,只有当前项目的一些基本信息。
接着我们在demo
目录下创建一个main.go
文件:
// demo/main.go
package main
import "fmt"
func main() {
fmt.Println("demo")
}
然后我们来学习如何引入一个第三方包,我们以github.com/A7cc/GoHello
(之前我用来测试用的)这个第三方包为例子实现引入包。我们需要先将依赖包下载到本地同时在go.mod
中记录依赖信息,然后才能在我们的代码中引入对应的包。
8.2 下载第三方依赖包
下载依赖有两种方法:
- 第一种方法是在项目目录下使用终端执行
go get
命令手动下载依赖的包:
可以看到PS C:\Desktop\demo> go get -u github.com/A7cc/GoHello go: added github.com/A7cc/GoHello v0.1.0 // 上面这种方法会下载最新发布的版本,如果我们需要指定版本,只需要在url的最后拼接@指定版本号即可 PS C:\Desktop\demo> go get -u github.com/A7cc/GoHello@v0.1.0
go.mod
的内容添加了一行:require github.com/A7cc/GoHello v0.1.0 // indirect
行尾的indirect
表示该依赖包为间接依赖,说明在当前程序中的所有import
语句中没有发现引入这个包。
同时还会生成go.sum
文件:
如果依赖包没有发布任何版本则会拉取最新的提交,最终go.mod
中的依赖信息会变成类似下面这种由默认v0.0.0
的版本号和最新一次commit
的时间和hash
组成的版本格式:
// 这里是我举例的demo,由于已经有发布版本了所以不会出现下面这种情况
require github.com/A7cc/GoHello v0.0.0-20220820074646-45b0acd320e
如果想指定下载某个commit
对应的代码,可以直接指定commit hash
,不过没有必要写出完整的commit hash
,一般前7位即可。例如:
// 我们通过commit下载v0.1.0版本的
PS C:\Desktop\demo> go get github.com/A7cc/GoHello@e876c7c
go: added github.com/A7cc/GoHello v0.1.0
另外在执行go get
命令还有其他方法:
运行
go get -u
将会升级到最新的次要版本或者修订版本(x.y.z, z是修订版本号, y是次要版本号)
运行go get -u=patch
将会升级到最新的修订版本
运行go get package@version
将会升级到指定的版本号version
- 第二种方式是我们直接编辑
go.mod
文件,将依赖包和版本信息写入该文件。我们修改demo/go.mod
文件内容如下:
然后在项目目录下使用终端执行module demo go 1.18 require github.com/A7cc/GoHello latest // latest表示对外发布的最新版本 // 当然了如果想下载知道版本,直接将latest改为对应的版本即可
go mod download
下载依赖包:
如果不输出其它提示信息就说明依赖已经下载成功,此时PS C:\Desktop\demo> go mod download
go.mod
文件已经更新到对应版本!
这种方法同样支持指定想要下载的commit
进行下载,例如直接在go.mod
文件中按如下方式指定commit hash
,这里只写出来了commit hash
的前7位,然后在项目目录下使用终端执行go mod download
即可:
module demo
go 1.18
require github.com/A7cc/GoHello e876c7c
8.3 第三方依赖包的使用
下载好依赖包后,我们引入该包,使用里面的函数方法并编译运行:
// demo/main.go
package main
import (
"fmt"
"github.com/A7cc/GoHello"
)
func main() {
GoHello.PrintHello()
fmt.Println("demo")
}
// Hello World!这是Go的测试库!
// demo
Go
语言支持在一个项目下定义多个包,比如我们在demo
项目内部创建一个新的包——test
,此时新的项目目录结构如下(必须要有go.mod
文件去确定test
包的位置):
demo
├ go.mod
├ go.sum
├ main.go
└ test
└ test.go
其中demo/test/test.go
文件内容如下:
// 注意这里的包是test包不是main,因为它不是完整的程序
// 这里的包名、文件名和文件夹尽量一致,因为在引入包时不容易混淆,当然也可以不一致,这时候引入包的名字也行,文件的名字也行,不过建议引入的是包名
package test
import "fmt"
func Run() {
fmt.Println("正在运动!")
}
此时想要在当前项目目录下的其他包或者main.go
中调用这个Run
函数需要在main.go
中引入该包,然后调用Run
方法:
// demo/main.go
package main
import (
"demo/test" // 导入当前项目下的包,这种方式引入当前文件夹的包需要在终端`go mod init 当前文件夹的名字`,即当前文件夹创建这个包
"fmt"
"github.com/A7cc/GoHello" // 导入github上第三方包
)
func main() {
// 调用第三方的包
GoHello.PrintHello()
fmt.Println("demo")
// 调用本地的包
test.Run()
}
从上面的示例可以看出,项目中定义的包都会以项目的导入路径为前缀,一般是在项目当前路径下索引的。如果需要索引其他位置的包,可以使用如下方法。
首先在go.mod
文件中使用replace
语句将依赖临时替换为本地的代码包,例如在我的电脑上有另外一个名为Desktop/demo2
的项目,它位于demo
项目同级目录下:
├ holiday
│├ go.mod
│├ go.sum
│├ main.go
│└ test
│ └ test.go
└ demo2
├ go.mod
└ demo2.go
我们可以在demo/go.mod
文件中正常引入Desktop/demo2
包,这里demo2
包的内容为:
// go.mod
module demo2
go 1.18
// demo2/main.go
// 注意这里的包是demo2包不是main
package demo2
import "fmt"
func Run() {
fmt.Println("这是demo2包!")
}
然后像下面的示例那样使用replace
语句将这个依赖替换为使用相对路径表示的本地包:
module demo
go 1.18
require github.com/A7cc/GoHello v0.1.0
require Desktop/demo2 v0.0.0
replace Desktop/demo2 => ../demo2
根据这个原理我们可以使用replace
将项目依赖中的某个包,替换为其他版本的代码包或我们自己修改后的本地代码包。
PS:看上面的路径可能会有点绕,但是我们只需要记住在Golang
中,没有相对路径这一说,它只有相对项目路径!!!
8.4 go.mod文件
go.mod
文件中记录了当前项目中所有依赖包的相关信息,声明依赖的格式如下:
require module/path v1.2.3
// require:声明依赖的关键字
// module/path:依赖包的引入路径
// v1.2.3:依赖包的版本号。支持以下几种格式:
// latest:官方发布的最新版本
// v1.0.0:详细版本号
// commit hash:指定某次commit hash
引入某些没有发布过tag
版本标识的依赖包时,go.mod
中记录的依赖版本信息就会出现类似v0.0.0-20210218074646-139b0bcd549d
的格式,由版本号、commit
时间和commit
的hash
值组成:
8.5 go.sum文件
使用go module
下载了依赖后,项目目录下还会生成一个go.sum
文件,这个文件中详细记录了当前项目中引入的依赖包的信息及其hash 值。go.sum
文件内容通常是下面的格式:
<module> <version>/go.mod <hash>
或者:
<module> <version> <hash>
<module> <version>/go.mod <hash>
不同于其他语言提供的基于中心的包管理机制,例如 npm
和 pypi
等,Go
并没有提供一个中央仓库来管理所有依赖包,而是采用分布式的方式来管理包。为了防止依赖包被非法篡改,Go module
引入了go.sum
机制来对依赖包进行校验。说白了,go.sum
就是为了校验go.mod
里面的包是否当前使用的包。
8.6 依赖的保存位置
Go module
会把下载到本地的依赖包会以类似下面的形式保存在 $GOPATH/pkg/mod
目录下,每个依赖包都会带有版本号进行区分,这样就允许在本地存在同一个包的多个不同版本。
mod
├ cache
├ cloud.google.com
├ github.com
└ A7cc
├ GoHello@v0.0.0-20220820074646-45b0acd320e
├ GoHello@v0.1.1
└ GoHello@v0.1.0
...
如果想清除所有本地已缓存的依赖包数据,可以执行 go clean -modcache
命令。
8.7 依赖的移除
我们在代码中删除依赖代码后,相关的依赖库并不会在go.mod
文件中自动移除。这种情况下我们可以使用下面这个命令更新go.mod
中的依赖关系:
go mod tidy
8.8 编辑go.mod
文件的依赖——go mod edit
- 格式化
因为我们可以手动修改go.mod文件,所以有些时候需要格式化该文件。Go提供了一下命令:
go mod edit -fmt
添加依赖项
go mod edit -require=golang.org/x/text
移除依赖项
如果只是想修改go.mod
文件中的内容,那么可以运行go mod edit -droprequire=package path
,比如要在go.mod
中移除golang.org/x/text
包,可以使用如下命令:
go mod edit -droprequire=golang.org/x/text
关于go mod edit
的更多用法可以通过go help mod edit
查看。
玖 使用go module发布包
9.1 上传和发布包
当我们需要发布一个自己编写的代码包到公司内部或者github.com
仓库上。首先我们需要在自己的github
上创建一个项目,例如创建和发布一个名为GoHello
的项目:
然后再我们本地目录创建一个GoHello
项目目录,在GoHello
项目目录下,初始化该项目,创建go.mod
文件,需要注意的是这里定义项目的引入路径为项目的URL
:
go mod init github.com/A7cc/GoHello
接着在该项目下创建GoHello.go
文件,内容为:
// GoHello.go
package GoHello
import "fmt"
func PrintHello() {
fmt.Println("Hello World!这是Go的测试库!")
}
然后将该项目的代码 push
到自己的仓库的远端分支,这样就对外发布了一个Go
包:
git init \\ 在目录中创建新的 Git 仓库
git add. \\ 将项目添加到仓库
git commit -m "第一次提交" \\ 把项目提交到本地的 Git 仓库,-m 后的内容是对本次提交内容的注释
接着使用SSH加密传输将本地仓库与Github仓库建立链接,首先创建SSH KEY
,在前面的终端运行:
ssh-keygen -t rsa -C "youremail@example.com"
在对应的目录下的.ssh
目录里可以看到id_rsa
和id_rsa.pub
这两个文件:
登录Github
找到右上角的图标,打开点进里面的Settings
,再选中里面的SSH and GPG KEYS
,点击右上角的New SSH key
,Title
里面随便填,再把刚才id_rsa.pub
里面的内容复制到Title
下面的Key
内容框里面,最后点击Add SSH key
,这样就完成了SSH Key
的加密:
// 将本地仓库与Github仓库进行关联
git remote add origin https://github.com/A7cc/GoHello.git
// 把本地库的所有内容推送到远程仓库
git push -u origin master
这时我们就可以使用go get -u github.com/A7cc/GoHello
下载并使用这个包!一个设计完善的包应该包含开源许可证及说明文档等内容,并且我们还应该维护并适时发布适当的版本,github
上发布版本号使用git tag
为代码包打上标签:
// -a是标签名字
// -m是对本次提交内容的注释
git tag -a v0.1.0 -m "发布版本v0.1.0"
// 将本地的 v0.1.0 分支推送到 origin 主机的 v0.1.0 分支
git push origin v0.1.0
经过上面的操作我们就发布了一个版本号为v0.1.0
的版本。在Go modules
中建议使用语义化版本控制,其建议的版本号格式如下:
- 主版本号:发布了不兼容的版本迭代时递增
- 次版本号:发布了功能性更新时递增
- 修订号:发布了
bug
修复类更新时递增
9.2 发布新的主版本包
假设我们现在的GoHello
包需要提交交互的输入,需要传参:
package GoHello
import "fmt"
func PrintHello(name string) {
fmt.Println("Hello World!这是Go的测试库!")
fmt.Println("你好!用户:", name)
}
可以看到我们的修改后的项目与之前的版本并不兼容或者说改动的比较巨大影响之前版本的使用,那么我们就需要递增添加一个v2
版本,做法是修改当前包的引入路径:
module github.com/A7cc/GoHello/v2
go 1.18
修改后提交代码到github.com
上:
git add .
git commit -m "添加了交互"
git tag -a v2.0.0 -m "release version v2.0.0"
git push origin v2.0.0
这样在不影响使用旧版本的用户的前提下,我们新的版本也发布出去了。想要使用v2
版本的代码包的用户只需按修改后的引入路径下载即可:
go get github.com/q1mi/hello/v2@v2.0.0
在代码中的实现只需要注意后面追加版本v2
即可:
// demo/main.go
package main
import (
"Desktop/demo2"
"demo/test" // 导入当前项目下的包
"fmt"
"github.com/A7cc/GoHello/v2" // 引入v2版本
)
func main() {
GoHello.PrintHello("A7cc")
fmt.Println("demo")
test.Run()
demo2.Run()
}
9.3 废弃已发布版本包
如果某个发布的版本不再想让用户使用时,我们可以使用retract
声明该版本是废弃版本,例如我们在GoHello/go.mod
文件中按如下方式声明即可对外废弃v0.1.1
版本:
module github.com/a7cc/GoHello
go 1.18
retract v0.1.1
用户使用go get
下载v0.1.1
版本时就会收到提示,催促其升级到其他版本。