Go的包机制

Posted by 皮皮潘 on 01-19,2022

Go 包是 Go 语言的基本组成单元。一个 Go 程序就是一组包的集合,所有 Go 代码都位于包中

golang的所有文件都需要指定其所在的包,包有两种类型,一种是main包,使用package main在代码的最前面声明,另外一种就是非main包,在main包中可以有唯一的一个main函数,这个函数也就是程序的入口,也只有main包可以编译成为可执行的文件

go使用package来管理源文件,package必须在一个文件夹内,且一个文件夹内也只能有一个package,但是一个文件夹可以有多个文件,也就是说多个文件都是同一个package在同一个文件夹下面,且其下的方法命名不能重复,也就是可以看作是一个文件拆分成了多个文件,与其他语言不同的是,在GoLang中文件夹名、包名以及文件名不需要相同,一个包可以分散在不同的同级文件里,只要都声明为一个包名即可

当需要导入一个package时,import “xxx/xxx/xxx”中的xxx/xxx/xxx是包所在的路径而非包名,按约定路径的最后一段与包名应该是相同的,这样可以方便地猜测包名是什么,但是正如上文所说GoLang中文件夹名、包名以及文件名允许不同,在这种情况下就需要进入源码查看包名并通过真正的包名去使用包中的方法与结构体

想要将包发布出去可以简单地使用github创建对应的仓库,然后将源代码放上去并配置版本号,接下来运行go get对应的URL或者go run都会从import语句中解析并下载第三方包到$GOPATH/src目录下对应路径的文件夹下,,由于Github往往会被墙,因此可以采用Proxy进行包下载的代理

在go1.12之前都统一使用GOPATH这样的一个集中文件夹进行依赖的管理,开发者通过go get类似git clone一样将第三方包的源码从github或者其他类似的网站上获取,然后打包,处理依赖,这样的一个好处是把分散式的github开源包进行了本地的集中式处理,从而处理依赖时会比较方便因为本地什么都有了,但是这也带来了版本依赖上的问题,因此从go1.12开始引入了go Module进行包管理,即go的软件包都可以声明为module,同时淡化了GOPATH,之所以说是淡化是因为虽然用户不需要配置GOPATH了,但是GOPATH依然存在着,也即所有的包依然还是统一存在一个隐式的GOPATH下面的,默认是用户目录的go文件夹下面

由于没有了显式的GOPATH,开发者的项目也就不需要像之前一样放在GOPATH/src下面了,之前如果不放在GOPATH/src下面的话go工具就会找不到对应的包,因为go工具仅仅会在GOPATH/src以及GOROOT/src两个路径下面寻找,通过使用go Module,开发者可以任意创建一个文件夹作为项目,但是需要使用go mod init xxx初始化模块生成对应go.mod,其中xxx是对应的module的名称,一个module下面会有多个package,module名称可以看作是一个命名空间,在引入该module下的package时,不管是内部项目引入还是外部项目引入,都可以使用module的名称再加上package所在文件夹的相对路径的方式进行引入

当引入外部的三方包时,go会检测项目中的import语句,并尝试根据go.mod的依赖引用关系导入三方包,如果本地没有就会像go get一样从远程拉取并放置到GOPATH/pkg/mod目录下,并自动更新go.mod,同时也可以使用go mod tidy手动更新,除此之外在go.mod中的require指令后面可以跟软件包名和版本号从而实现版本控制

在需要修改三方包的情况下,可以简单地将依赖包复制到项目的vendor文件夹下面(go也会在在 vendor 目录下查找对应的依赖包),然后进行修改,最后通过修改go.mod使用replace指令将对应的包指向当前项目下修改了的包即可