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的包的特性有以下几点:
$GOAPTH
里添加自己工程的路径;.go
文件必须存放在一个独立的文件夹下;import
关键字,该关键字提供了若干方式引入包;在 GOPATH 模式下,执行 go build 或 go run 时,在 vendor 目录、GOPATH 目录、GOROOT 目录都可能存在依赖库(标准库、第三方库等),将依次按照如下的目录过程寻找引用的依赖:
- 在当前目录下的 vendor 目录查找依赖的 package
- 当前目录不存在 vendor 目录,则去上一级目录寻找
- 重复步骤 2 直到进入 $GOPATH/src 目录
- 没有在 vendor 目录中查找到依赖包,则进入 $GOROOT 目录查找依赖包
- $GOROOT 目录也没有依赖包,则进入 $GOPATH 目录寻找依赖包
导入包的查找顺序,所以自定的包需要配置完整的路径,否则会找不到包,具体的引入方式如下:
import 项目根路径/项目内路径/所需的包
源文件的名称不会影响包名调用函数,方法,变量等。
GOPATH 是 Go语言中使用的一个环境变量,它使用绝对路径提供项目的工作目录。运行和构建项目时,编译器就会从该目录下寻找。如果不配置 GOPATH,即使处于同一目录,代码之间也无法通过绝对路径相互调用。
GOPATH,是构建Go工程结构的实现,如果想要构建一个基于Go语言的项目,就需要将这个项目的目录添加到 GOPATH 中。因此go工程构建时需要添加GOPATH环境变量,多个项目之间可以使用;
分隔。
Go项目的构建,运行和发布都在该工程目录下。GOPATH不同于Java的Maven,Gradle等项目管理工具,能够一键化构建工程目录并实现相关依赖的管理,项目的构建,打包,发布等一切工程需求。GOPATH更像一个更规范,按照其规定来构建工程目录才能实现go项目的开发。
命令行中运行go env命令能够看到go的配置环境信息。
GOPATH是go语言早期,用来处理Go语言源码、包管理的工具。Go语言的程序编写基本以源码方式, GOPATH 作为工作目录和一套完整的工程目录规则。如下,
在 GOPATH 指定的工作目录下,代码需要保存在 $GOPATH/src
目录下;
$GOPATH/bin
目录用于工程经过 go build
、go install
或 go get
等指令后,会将产生的二进制可执行文件。
生成的中间缓存文件会被保存在 $GOPATH/pkg
下。
GOPATH项目管理存在以下问题
$GOPATH/src
目录的源码一整个提交。GOPATH实现多工程只能修改GOPATH的环境变量,指向新的路径。这也是开发者容易遗忘的部分。在很多IDE(集成开发工具)中,都会有系统GOPATH,和项目GOPATH的区别。
在window系统中使用GOPATH只需要配置环境变量,如下:
在linux系统中也是如此,通过
export
命令进行export GOPATH=绝对路径
使用 export 指令可以将当前目录的值设置到环境变量 GOPATH中。
随着Go语言的发展,GOPATH不再是主流的构建工程的规范。官方推荐了GOMOD
工具,在go的1.11版本之后无需手动配置环境变量,使用go mod全新的项目管理方式。(将在下下节列出)
无论基于那种方式构建项目,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 pprof
Go语言工具链中的 go pprof 可以帮助开发者快速分析及定位各种性能问题,如 CPU 消耗、内存分配及阻塞分析。
随着Go的发展官方推出了新的项目管理工具GOMOD。GOMOD弥补了GOPATH的众多不足,为Go开发提供了很大的方便。
使用GOPATH缺点:
相来说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
可以查看相关环境配置。
GO111MODULE 有三个值:off, on和auto(默认值)。
当modules功能启用时,依赖包的存放位置变更为$GOPATH/pkg,允许同一个package多个版本并存,且多个项目可以共享缓存的 module。
go的环境命令go env
提供了参数可以修改GOMOD的状态,如下:
go env -w GO111MODULE=on 或者 go env -w GO111MODULE=auto
在go项目开发时需要下载各种依赖包,由于go的服务器在国外,因此需要使用代理
GOPROXY
配置go依赖库的国内镜像下载地址,否者使用国外地址会非常卡。(GOPROXY章节叙述)
go中包分为三种:1.系统内置包 2. 自定义包 3.第三方包。
对于前两种go mod提供了,内置和自定义的引入比较方便,直接引入包名即可,第三方包需要下载到本地,通过go get,go download
即可。
第三方包可以在https://pkg.go.dev/上寻找,是和NPM类似的包管理仓库。
发展到go mod才算一个项目管理的工具,使用 go mod 的工程,需要使用go mod 命令行来构建项目,且项目最明显额特征是有一个go.mod
文件。
在 go mod 包管理工具提供下面完成 go mod 的初始化、依赖文件检查更新、以及自动建立 vendor 目录等。
表达式:go mod
// 常用命令
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]
可以指定
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 get
和go 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文件有如下几个元素,
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的一个功能就是指定特定版本,让项目组每个开发者使用同一个版本号进行开发。
proxy是代理服务器的意思。国内网络有防火墙的存在,导致有些Go语言的第三方包无法直接通过go get命令获取。GOPROXY 是Go语言官方提供的一种通过中间代理商来为用户提供包下载服务的方式。要使用 GOPROXY 只需要设置GOPROXY 为代理的地址即可。
国内使用go的配置代理,最常用的就是七牛维护的镜像goproxy.cn
,相关配置变量如下
go env -w GOPROXY=https://goproxy.cn,direct
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模块的开发人员使用模块版本号的每个部分来表示版本的稳定性和向后兼容性。对于每个新版本,模块的发布版本号具体反映了自上一版本以来模块更改的性质。