[Go 入门] 第十二章 使用包实现代码复用
Go 入门系列参考于互联网资料与 人民邮电出版社 《Go 语言入门经典》 与 《Effective Go》,编写目的在于学习交流,如有侵权,请联系删除
包用于代码编组, 以便在Go程序中导入并使用它们, 本文内容:
导入包
Go 程序以 package
语句打头,main
包是一种特殊的包,其特殊之处在于不能导入。对 main
包唯一的要求是,必须声明一个 main
函数,这个函数不接收任何参数且不返回任何值。 main
就是程序的入口
1 |
|
在 main 包中,可使用import
声明来导入其他包。导入包后,就可使用其中被导出的(即公有的)标识符。在 Go 语言中,标识符可以是变量、常量、类型、函数或方法。这让包能够通过接口提供各种功能。例如 math
包提供了常量 Pi
1 |
|
导入包并使用其中导出的标识符,是重要标准库和其他第三方代码的基本方式。这种方式虽然简单,但您必须理解,灵活性和代码复用在很大程序上都是通过这种方式实现的
理解包的用途
要了解如何使用包,先得知道该使用哪个。在标准库中,Go语言采用了一致的命名约定。Go语言中,包名短小且精悍又含义丰富。 strings
包包含用于处理字符串的函数,bytes
包包含用于处理字节的函数。
假设要在程序中操作字符串,可以通过阅读标准库包清单,会发现存在着 strings
这样一个包,但如何知道它提供了那些功能呢? Go 语言的文档很完善,而对于标准库中的包,都有卓越的文档,对于 stings
包,其文档可在 Go 语言官网找到
在这个文档中,列出了所有被导出的标识符。假设您需要在程序中将字符串转换为小写,通过查看文档可知,有一个名为 ToLower
的函数。文档还指出这个函数将一个字符串作为参数,并返回一个字符串
func ToLower(s string) string
文档简单地描述了这个函数的作用,还包含一些演示其用法的示例代码。对于这些示例代码,可以直接在浏览器执行它们。如果还需要更深入地了解这个函数,还可以查看 strings
的源代码
使用第三方包
标准库提供了很多功能,但Go语言的设计理念是确保核心标准库小巧而稳定,因此标准库没有提供连接到数据库,分析文件格式以及实现身份验证协议的功能。不用多久,标准库就无法满足编写的需求了,这种情况下,通常有两种选择:
- 自己编写解决问题的代码
- 寻找能够解决问题的包 (或库代码)
大部分程序员很有可能选择第二种做法。然而,在程序中添加额外的依赖要三思而行,因为这可能影响程序的稳定性和可维护性。考虑使用第三方库时,应该考虑:
- 是否明白了这些代码是做什么的
- 这些代码值得信任吗
- 这些代码的维护情况如何
- 真的需要这个库吗
回答这些问题时,请注意:
明白包的作用至关重要,优秀的第三方包都有卓越的文档,这些文档通常遵循 Go 语言文档约定,指出了它们导出了那些标识符。通过阅读文档,可确定包是否提供了您所需的功能
确定第三方包值得信任很重要。别忘了,将包导入程序后,它就能访问底层的操作系统。要确定第三方包的可信任程序,可了解还有多少人在使用它、是否有同事推荐,还可阅读其源代码
考虑到软件的特征,第三方包不可避免地存在 bug,不要选择几年都没有更新的包,而应选择开发方积极维护的第三方包,因为这意味着随着时间的推移,这样的包会越来越稳定
导入第三方包会增加程序的复杂性。很多时候导入一个包只为了使用其中一个函数,这种情况下,可以复制这个函数,而不导入整个包
安装第三方包
要使用第三方库,必须向标准库一样 import
语句导入它
在下面的示例中,将使用 Go 小组开发的 stringutil
包。这是一个简单的第三方包,只有一个函数被导出——Reverse
。这个函数将一个字符串作为参数,将该字符串反转并返回结果。
要使用第三方包,必须先使用命令 go get
安装它。这个命令默认随 Go 一起安装了,它将指向远程服务器中包的路径作为参数,并在本地安装指定的包
go get github.com/golang/example/stringutil
这个包被安装到环境变量 GOPATH 指定的路径中,因此可在程序中使用它。要查看这个包的源代码,可打开目录src中的文件。包的安装目录如下:
1 |
|
安装这个包后,就可以导入它了
1 |
|
执行后,它将反转 Hello
:
olleH
通常,第三方包依赖于其他第三方包。命令 go get
会下载依赖的第三方包,而无需手动安装每个包依赖的第三方包
管理第三方依赖
很多语言有包管理器,可简化使用第三方包的工作:
- Python 有 pip
- .NET 有 Nuget
- Ruby 有 RubyGems
- Node.js 有 npm
在1.5版本时,Go 1.5引入了文件夹vendor
,这能够让第三方模块添加到项目目录了下的文件夹vendor
中,并将所有的包文件移到这个文件夹中,这样可以不全局地安装包,而仅在项目中安装它。对于前面安装的 stringutil
包移到vendor
目录后,仅能在项目中使用它, 它并不是全局的,这样的做法有一些优点:
- 可锁定的版本,为此只需要特定版本赋值到项目目录中
- 构建服务器无需下载依赖,因为它包含在这些项目中
如果您使用过包管理器,可能发现这种做法会有一些缺点
- 依赖必须包含在仓库中
- 使用的是包的哪个版本不明显
- 没有处理包的依赖
- 无法在清单文件中准确地指定提交或分支
当前,程序员必须手工管理复杂的依赖,有很多第三方工具使用 vendor
文件夹支持安装特定的包版本
go 1.11 版本后推出了 go module
功能,go module
只需要在本地保存 go.mod
文件以及用作校验的 go.sum
文件即可,并不用在 vendor
中下载保存依赖
关于 go module
的使用在后续的文章中会有单独的介绍,届时会更新本文,插入链接
创建包
除了使用第三方包以外,有时还可能需要创建包。文本将创建一个示例包,并将其发布到 Github 以便与人分享,这是一个处理温度的包,提供了在不同温度格式之间进行转化的函数,这创建一个名为 temperature.go 的文件,并在其中添加
1 |
|
导入这个包后,就可使用其中所有以大写字母打头的标识符了。要创建私有标识符(变量,函数等),可让其以小写字母开头
为了测试这个包,可以创建一个 temperature_test.go
的测试文件,目前而言,只需知道这个文件对这个包进行测试就行了,后面的文章中将会单独介绍 测试
temperature.go
1 |
|
temperature_test.go
1 |
|
执行后:
1 |
|
对于发布到网上的包,从用户的角度考虑问题很重要,因此推荐在包中包含以下文件:
- 指出用户如何使用代码的 LICENSE 文件(如开源协议)
- 包含有关包的说明信息的 README 文件
- 详细说明包经过了哪些修改的 Changelog 文件
作为代码的创始者,如何授权开源由自己决定。有很多的开源方式,有些要求宽松,有的要求严格
在 ReadME 文件中,应包含有关包的信息,如何安装包以及如何使用包。您可能还想在其中包含有关如何参与改进项目的信息。如果将包发布到 Github,需要使用 Markdown 格式编写
在 Changelog 文件中,应列出对包所做的修改,这可能包含功能添加情况和API删除情况。通常,使用 git 标签来指示发布情况,能够让用户轻松地下载特定版本
问题列表
如何将第三方包依赖复制到文件夹 vendor 中
可以使用
govendor
作为包的管理工具,但随着 go 的版本更新,推荐使用go module
作为包管理工具