GO Package、GOPATH、GOMOD、GOROOT、GOPROXY、版本迭代

Go包的概念

Go语言是使用包来组织源代码的,包(package)是多个 Go 源码的集合,是一种代码复用方式。Go语言中为我们提供了很多内置包,如 fmt,io 等。任何Go源代码文件必须属于某个包,同时源码文件的第一行有效代码必须声明包名称。

package pacakgeName

包在工程中对应目录(dictionary),目录管理者这些包,共同组成go应用。在早期的go中通过GOPATH设置go工程目录,go项目需要在该目录下,工程的树型结构管理者go的源码。

包名为main 的包为应用程序的入口包,编译不包含 main 包的源码文件时不会得到可执行文件。
一个文件夹下的所有源码文件只能属于同一个包,同样属于同一个包的源码文件不能放在多个文件夹下。

通过使用import关键字导入需要使用的其他包,import 导入语句通常放在源码文件开头包声明语句的下面;导入的包名需要使用双引号包裹起来;包名是从GOPATH/src/ 后开始计算的,使用/ 进行路径分隔。go的内置包直接导入无需路径。

导入包时也支持相对路径../,./但都基与GOPATH/src/ 路径下。

总的来说,Go的包的特性有以下几点:

  1. go 不会自动查找当前路径下的文件,必须先在$GOAPTH里添加自己工程的路径;
  2. 自定义包里面对外提供的API,命名首字母必须大写,及首字母的大小写控制着访问权限;
  3. 包的编译和安装时规定,.go文件必须存放在一个独立的文件夹下;
  4. 引入包通过import关键字,该关键字提供了若干方式引入包;

在 GOPATH 模式下,执行 go build 或 go run 时,在 vendor 目录、GOPATH 目录、GOROOT 目录都可能存在依赖库(标准库、第三方库等),将依次按照如下的目录过程寻找引用的依赖:

  1. 在当前目录下的 vendor 目录查找依赖的 package
  2. 当前目录不存在 vendor 目录,则去上一级目录寻找
  3. 重复步骤 2 直到进入 $GOPATH/src 目录
  4. 没有在 vendor 目录中查找到依赖包,则进入 $GOROOT 目录查找依赖包
  5. $GOROOT 目录也没有依赖包,则进入 $GOPATH 目录寻找依赖包

导入包的查找顺序,所以自定的包需要配置完整的路径,否则会找不到包,具体的引入方式如下:

import 项目根路径/项目内路径/所需的包

源文件的名称不会影响包名调用函数,方法,变量等。

GOPATH

GOPATH 是 Go语言中使用的一个环境变量,它使用绝对路径提供项目的工作目录。运行和构建项目时,编译器就会从该目录下寻找。如果不配置 GOPATH,即使处于同一目录,代码之间也无法通过绝对路径相互调用。

GOPATH,是构建Go工程结构的实现,如果想要构建一个基于Go语言的项目,就需要将这个项目的目录添加到 GOPATH 中。因此go工程构建时需要添加GOPATH环境变量,多个项目之间可以使用;分隔。

Go项目的构建,运行和发布都在该工程目录下。GOPATH不同于Java的Maven,Gradle等项目管理工具,能够一键化构建工程目录并实现相关依赖的管理,项目的构建,打包,发布等一切工程需求。GOPATH更像一个更规范,按照其规定来构建工程目录才能实现go项目的开发。

命令行中运行go env命令能够看到go的配置环境信息。

GOPATH是go语言早期,用来处理Go语言源码、包管理的工具。Go语言的程序编写基本以源码方式, GOPATH 作为工作目录和一套完整的工程目录规则。如下,

GO Package、GOPATH、GOMOD、GOROOT、GOPROXY、版本迭代_第1张图片

  1. 在 GOPATH 指定的工作目录下,代码需要保存在 $GOPATH/src 目录下;

  2. $GOPATH/bin 目录用于工程经过 go buildgo installgo get等指令后,会将产生的二进制可执行文件。

  3. 生成的中间缓存文件会被保存在 $GOPATH/pkg 下。

GOPATH项目管理存在以下问题

  1. GOPATH直接管理源码,多项目构建存在困难。
  2. GOPATH直接管理源码,版本迭代困难,只能将$GOPATH/src 目录的源码一整个提交。
  3. 使用第三方工具包时依赖管理困难。

GOPATH实现多工程只能修改GOPATH的环境变量,指向新的路径。这也是开发者容易遗忘的部分。在很多IDE(集成开发工具)中,都会有系统GOPATH,和项目GOPATH的区别。

在window系统中使用GOPATH只需要配置环境变量,如下:

GO Package、GOPATH、GOMOD、GOROOT、GOPROXY、版本迭代_第2张图片

在linux系统中也是如此,通过export命令进行

export GOPATH=绝对路径

使用 export 指令可以将当前目录的值设置到环境变量 GOPATH中。

随着Go语言的发展,GOPATH不再是主流的构建工程的规范。官方推荐了GOMOD工具,在go的1.11版本之后无需手动配置环境变量,使用go mod全新的项目管理方式。(将在下下节列出)

Go内置命令与工具命令

无论基于那种方式构建项目,GO的内置编译,运行,打包等命令,都是不会变的。

go build:用于编译代码,go build 有很多种编译方法,如无参数编译、文件列表编译、指定包编译等,使用这些方法都可以输出可执行文件。

go build (没有参数)在编译开始时,会搜索当前目录的 go 源码,编译源码后生成当前目录名的可执行文件并放置于当前目录下。
go build [文件列表]
go build -o [name] 指定打包名称

go clean:命令可以移除当前源码包和关联源码包里面编译生成的文件

-i 清除关联的安装的包和可运行文件,也就是通过go install安装的文件;
-n 把需要执行的清除命令打印出来,但是不执行,这样就可以很容易的知道底层是如何运行的;
-r 循环的清除在 import 中引入的包;
-x 打印出来执行的详细命令,其实就是 -n 打印的执行版本;
-cache 删除所有go build命令的缓存
-testcache 删除当前包所有的测试结果

go run命令会编译源码,并且直接执行源码的 main()函数,不会在当前目录留下可执行文件。相当于以脚本的形式运行go文件。

gofmt 代码格式化工具。传入了文件路径的话,会格式化这个文件,如果传入一个目录,会格式化目录中所有 .go 文件,如果不传参数,会格式化当前目录下的所有 .go 文件。

go install 和go build 命令类似,但是go install 只是将编译的中间文件放在 GOPATH 的目录下,而不是项目目录下。go install 是建立在 GOPATH 上的,无法在独立的目录里使用。

go get命令可以借助代码管理工具通过远程拉取或更新代码包及其依赖包,并自动完成编译和安装。

使用 go get 命令前,需要安装与远程包匹配的代码管理工具,如 Git、SVN、HG 等,参数中需要提供一个包名。
go get命令先下载源码包,然后执行 go install。工具会自动根据不同的域名调用不同的源码工具。
参数为远程包名:go get+ 远程包,如go get github.com/davyxu/cellnet分别表示域名/机构&作者名/项目名

go generate运行该命令时,它将扫描与当前包相关的源代码文件,找出所有包含//go:generate的特殊注释,提取并执行该特殊注释后面的命令。

go test命令,会自动读取源码目录下面名为 *_test.go 的文件,生成并运行测试用的可执行文件。

Go语言拥有一套单元测试和性能测试系统,仅需要添加很少的代码就可以快速测试一段需求代码。
单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。要开始一个单元测试,需要准备一个 go 源码文件,在命名文件时需要让文件必须以_test结尾。
go test命令一般不需要任何的参数,它会自动把你源码包下面所有 test 文件测试完毕,当然你也可以带上参数。
单元测试源码文件可以由多个测试用例组成,每个测试用例函数需要以Test为前缀func TestXXX( t *testing.T )
测试用例文件不会参与正常源码编译,不会被包含到可执行文件中。 测试用例文件使用go test指令来执行,没有也不需要 main() 作为函数入口。所有在以_test结尾的源码内以Test开头的函数会自动被执行。

go pprofGo语言工具链中的 go pprof 可以帮助开发者快速分析及定位各种性能问题,如 CPU 消耗、内存分配及阻塞分析。

GOMOD

工程管理的发展

随着Go的发展官方推出了新的项目管理工具GOMOD。GOMOD弥补了GOPATH的众多不足,为Go开发提供了很大的方便。

GO Package、GOPATH、GOMOD、GOROOT、GOPROXY、版本迭代_第3张图片

使用GOPATH缺点:

  • 代码开发必须在GOPATH src目录下。
  • 依赖手动管理
  • 依赖包没有版本可言

相来说GOPATH更像一个go开发规范,而不是项目管理工具。

后来又发展到了govendor解决了包依赖的问题,但是依赖包全都下载到项目vendor下,每个项目都把有一份,太冗余。vendor 目录下的依赖包还是需要手动加入,也没有依赖包的版本记录,那么 vendor 下的依赖包的进行升级更新也还是有困难。

go mod 在 1.11 版本中试验性加入 go ,在 1.13 版本后正式作为官方的包管理工具。

go mod加入了go.mod 文件、 GO111MODULE 变量、go build -mod 命令以及 GOPATH/pkg/mod ,它们决定了依赖的版本、依赖包存储位置以及编译过程的依赖包。

环境变量 GO111MODULE

使用GOMOD需要先开启功能,通过go env可以查看相关环境配置。

GO Package、GOPATH、GOMOD、GOROOT、GOPROXY、版本迭代_第4张图片

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

  • GO111MODULE=off,go命令行将不会支持module功能,寻找依赖包的方式将会沿用旧版本那种通过vendor目录或者GOPATH模式来查找。
  • GO111MODULE=on,go命令行会使用modules,对项目依赖管理,依赖包存放在 $GOPATH/pkg/mod 目录,多个项目可以共享缓存的 modules。
  • GO111MODULE=auto,默认值,go命令行将会根据当前目录来决定是否启用module功能。

当modules功能启用时,依赖包的存放位置变更为$GOPATH/pkg,允许同一个package多个版本并存,且多个项目可以共享缓存的 module。

go的环境命令go env提供了参数可以修改GOMOD的状态,如下:

go env -w GO111MODULE=on 或者 go env -w GO111MODULE=auto

GO Package、GOPATH、GOMOD、GOROOT、GOPROXY、版本迭代_第5张图片

在go项目开发时需要下载各种依赖包,由于go的服务器在国外,因此需要使用代理GOPROXY配置go依赖库的国内镜像下载地址,否者使用国外地址会非常卡。(GOPROXY章节叙述)

Go包管理

go中包分为三种:1.系统内置包 2. 自定义包 3.第三方包。

对于前两种go mod提供了,内置和自定义的引入比较方便,直接引入包名即可,第三方包需要下载到本地,通过go get,go download即可。

第三方包可以在https://pkg.go.dev/上寻找,是和NPM类似的包管理仓库。

GO Package、GOPATH、GOMOD、GOROOT、GOPROXY、版本迭代_第6张图片

GOMOD工具命令

发展到go mod才算一个项目管理的工具,使用 go mod 的工程,需要使用go mod 命令行来构建项目,且项目最明显额特征是有一个go.mod文件。

在 go mod 包管理工具提供下面完成 go mod 的初始化、依赖文件检查更新、以及自动建立 vendor 目录等。

表达式go mod [arguments]

// 常用命令
   go mod init        // 初始化 go.mod,将开启 mod 使用
   go mod tidy        // 添加或者删除 modules,取决于依赖的引用
   go mod vendor      // 复制依赖到 vendor 目录下
    
   // 其它命令
   go mod download  // 下载 module 到本地
   go mod edit     //  编辑 go.mod
   go mod graph    //  打印 modules 依赖图
   go mod verify   //  验证依赖
   go mod why      //  解释依赖使用

go mod init命令来创建一个go.mod文件来管理项目,如在项目project下初始化项目:go mod init project一个项目中必须要有main包和main方法。

当使用 go mod 的工程放在 GOPATH/src 目录下,可以直接用 go mod init 进行初始化,将自动检测 $GOPATH/src 后的目录作为包的 module
工程在 GOPATH 之外使用 go mod,在进行 mod 初始化时,需要给当前工程指定 moudle 目录

go mod download下载 go.mod 文件中指明的所有依赖。go download [-x] [-json] [modules]
GO Package、GOPATH、GOMOD、GOROOT、GOPROXY、版本迭代_第7张图片

可以指定path@version形式的下载包,也可以不带参数表示require元素中所有的依赖。

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

go mod graph查看现有的依赖结构。

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

go mod verify查询模块是否出错

go mod why查看包依赖源

go mod vendor导出项目所有的依赖到vendor目录,从mod中拷贝到项目的vendor目录。

go getgo mod download均可以下载依赖包,它们的主要区别式前者是go提供的下载命令,能够将依赖包,下载到指定目录,便于开发者引用;后者是go mod提供的命令,在moudles环境下下载依赖包,实现自动化管理。
另外在使用时也有区别,go get xxx@xxx是下载的方式,而go mod download下载是需要可以先引入go mod文件中直接用go download下载,也可以通过go download path@version下载。

了解go.mod文件

go mod 使用go.mod文件管理以来的版本,go.mod文件有如下几个元素,
GO Package、GOPATH、GOMOD、GOROOT、GOPROXY、版本迭代_第8张图片

module xx/xx/xx/v2
go 1.16
require (
        xx/xx/xx v1.3.3
        xx/xx/xx v0.0.0-20200330080233-e4ea8bd1cbed
	xx/xx/xx v2.2.1+incompatible
	xx/xx/xx v0.3.0 // indirect
)
exclude (
	xx/xx/xx v1.3.3-rc.0
)

replace xx/xx/xx => xx/xx v1.3.3

retract (
    v1.0.0 // 废弃的版本,请使用v1.1.0
)

元素的具体意义是:

module xx/xx/xx/v2是指该项目的module路径,/v2是指版本信息,可以省略。

go 1.16是指项目需要的最低go的版本


require()是项目需要的其他依赖:

-- xx/xx/xx v1.3.3指明了项目需要的依赖以及版本号。
-- xx/xx/xx v0.0.0-20200330080233-e4ea8bd1cbed是时间戳性质的版本号。
-- xx/xx/xx v0.3.0 // indirect是指依赖需要的依赖
-- xx/xx/xx v2.2.1+incompatible是指依赖的库的major版本大于引用的版本,不合规范。

exclude()指引用依赖时,跳过某些版本

replace xx/xx/xx => xx/xx v1.3.3指替换某些依赖

retract()声明废弃的版本

go 会自动生成一个 go.sum 文件来记录 dependency tree。go.mod的一个功能就是指定特定版本,让项目组每个开发者使用同一个版本号进行开发。

GOPROXY与版本迭代

proxy是代理服务器的意思。国内网络有防火墙的存在,导致有些Go语言的第三方包无法直接通过go get命令获取。GOPROXY 是Go语言官方提供的一种通过中间代理商来为用户提供包下载服务的方式。要使用 GOPROXY 只需要设置GOPROXY 为代理的地址即可。

国内使用go的配置代理,最常用的就是七牛维护的镜像goproxy.cn,相关配置变量如下

GO Package、GOPATH、GOMOD、GOROOT、GOPROXY、版本迭代_第9张图片

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

默认下载地址时go官方地址
GO Package、GOPATH、GOMOD、GOROOT、GOPROXY、版本迭代_第10张图片
使用上述命令修改为国内镜像

GO Package、GOPATH、GOMOD、GOROOT、GOPROXY、版本迭代_第11张图片

Java库的版本迭代一般会把Java源码打包为一个jar文件,上传到本地仓库或者中央仓库中。而对于go无需代码仓库,go以源码的方式实现版本迭代,上传源码到git仓库即可。

开发完一个go应用后通过git实现代码仓库管理和版本迭代。git管理代码只需要将源码上传到远程仓库即可。Go模块通过git提供的Tag标签给模块标记版本号。

# 创建一个标签
git tag 

# 创建一个带有注释的标签
git tag -a  -m 'your_tag_description'

# 列出所有的标签
git tag --list

# 创建一个标签
git tag 

# 删除一个标签
git tag -d 

# 删除远程仓库的标签
git push --delete origin 

# 推送一个标签到远程
git push origin 

# 推送多个本地标签到远程
git push origin --tags

当没有打过标签的版本号将是伪版本号

golang.org/x/lint v0.0.0-20200302205851-738671d3881b

当我们通过Git打标签之后,可能会是这样的:

golang.org/x/lint v0.0.1

GO模块的开发人员使用模块版本号的每个部分来表示版本的稳定性和向后兼容性。对于每个新版本,模块的发布版本号具体反映了自上一版本以来模块更改的性质。

GO Package、GOPATH、GOMOD、GOROOT、GOPROXY、版本迭代_第12张图片

你可能感兴趣的:(Go,golang)