Go 包管理

Package

go 的文件都以 package PACKAGE_NAME 开头,表示这个文件属于哪个包,如果是 package main 表示这个文件是可以运行的。同一目录下的文件的package名称都相同。

我们可以通过新建一个目录,在目录下新建若干 go 源文件的方式来创建自己的 package,每个 go 源文件的的 package 的名字都是统一的(即我们创建的包的名字),它们也都属于同一个包,不同源文件中定义的函数也都可以互相使用,并不存在需要先声明再调用的限制。在该目录下可以使用 go build 对我们的包进行编译。

在其他文件中,可以使用 import "path/to/PACKAGE_NAME"来导入包,从而引用包中的结构体、函数等等。go 不允许循环引用。使用 import ALIAS "path/to/PACKAGE_NAME" 的方式可以以别名的形式导入包。

go 也不允许导入未使用的包,如果我们需要使用某个包中的 init() 方法,但又不会使用这个包,可以使用import _ PACKAGE匿名导入。如果导入了未使用的包,编译会报错,一个比较好的方式是使用goimports工具,可以自动清除文件中未使用的导入包。对某个路径下的所有文件使用goimports的方法为:goimports -w path/

在package中,我们可以定义一系列的变量、常量、类型、结构体、方法、函数等,如果我们定义的变量、函数、etc…的名称是大写开头,则这些变量、函数对于调用这个包的外部调用者是可见的,如果是小写开头,则这些变量、函数就叫做unexported(未导出的),可以理解为私有方法,只有在包的内部才能使用这些变量、函数。这样的方式提供了安全性和更好的封装性,包的调用者不需要关心一些实现细节,而是只使用包提供的方法。

有些包中可能会需要一个初始化函数,来初始化一些全局变量,比如初始化某个map的长度,初始化一个数据库链接等等。在包中使用init()函数,则在初始化的时候,init()中的内容会自动执行。每个包都会以导入的顺序进行初始化,然后 main 函数才会开始执行。

另一种初始化包级变量的方式是手动定义可导出的初始化函数,比如InitMap(),然后在主函数的文件的init()函数中,手动调用这个包的InitMap()

Go Module

go提供了自己的包管理工具 go mod,在环境变量中配置export GO111MODULE=on即可使用。go mod可以自动添加、删除、下载依赖,支持从常用的git仓库如GitHub下载依赖,非常易于使用。

在项目中使用 go mod init,会初始化一个go.mod文件,里面记录了项目文件中依赖的包以及对应版本。使用go mod tidy,则会自动整理(添加、删除)依赖,包括下载依赖包,但不会更新依赖包在 go.mod中记录的版本。想要将某个依赖更新到最新版,可以使用go get XXX。关于go get有几点冷知识:

  • go get XXX某个包,如果这个包之前是用语义化版本控制的,也就是git上打tag的v1.0.4的这种形式,那么go get只会更新这个包到最新的语义化版本,也就是说如果有最新的commit没有打tag,使用go get还是不能更新到这个commit,这时可以用get get XXX@master
  • go get -u XXX中的-u参数不是更新到最新版本的意思,而是指同时更新该依赖中所有参与编译的依赖到最新版本
  • go get的目标package为main,还会同时编译安装二进制到$GOPATH/bin

如果多个依赖包中对某个特定依赖包的依赖版本不同,go mod会选择所有依赖版本中最高的那个版本

如果想要强制指定某个依赖的版本,比如因为兼容性问题不想更新到最新版的时候,则可以在go.mod中使用replace,比如:

replace github.com/golang/protobuf => github.com/golang/protobuf v1.3.5

使用go mod graph可以查看所有依赖项之间的依赖关系,比如用go mod graph | grep XXX可以查到某个依赖项是如何被依赖的。

常见报错:

  • 升级了某个依赖之后,编译报错。原因一般是使用了go get -u同时升级了依赖的依赖,而导致了不兼容,所以如无必要,不使用-u参数
  • unknown revision v1.X.X:该依赖包的远程的某个版本被删掉了,这时编译时就会因为找不到对应版本而报错,解决方法是将依赖更新到最新版本

以上是 Go 包管理 的全部内容, 来源链接: utcz.com/z/264381.html

回到顶部