本文翻译于原文。
引言
本文说明了简单Go包的开发过程,并介绍了使用go tool来feth,build和安装Go包和命令的标准方法。
go工具需要你以特定方式管理代码。请仔细阅读本文。它解释了以最简单的方式启动和运行Go安装。
代码管理
综述
- Go程序员一般将他们的Go代码放在一个工作区中。
- 一个工作区包含了许多版本控制仓库(例如,由git管理)。
- 每个仓库包含一个或多个包。
- 每个包由同一个目录中的一个多个Go源文件组成。
- 包目录路径决定了它的 import 路径。
工作区
工作区是由根目录下有三个目录的层级目录组成的:
src包含Go源文件,pkg包含包对象,bin包含可执行命令。
go工具构建源包,并将产生的二进制文件安装到pkg和bin目录中。
src子目录一般包含多个版本控制仓库(例如 Git或Mercurial),用于跟踪一个或多个源包的开发。
以下是一个例子,让你看下实际中的工作区是长什么样的:
上面的目录树展示了一个包含两个库(example和image)的代码库。example包含两个命令(hello和outyet)和一个函数包(stringutil)。image库包含bmp包和其它东西。
一个典型的工作区会有许多包含包和命令的源库。大多数Go开发人员将所有的Go源码和依赖保存在一个工作区中。
命令和函数包是从不同的源包构建出来的。我们将在之后讨论。
GOPATH环境变量
GOPATH环境变量指定工作区的位置。默认在home目录下的go目录中,在Unix中是$HOME/go, Plan 9中是$home/go,在Windows上是%USERPROFILE%\go(通常是C:\Users\YourName\go)。如果你想要在不同路径下工作,就需要设置到那个目录路径的GOPATH。(另一个常用配置是设置GOPATH=$HOME。)注意GOPATH不能和你的Go安装路径相同。
go env GOPATH命令打印当前有效的GOPATH;如果环境变量未设置会打印默认位置。
为了方便起见,将工作区的bin子目录加到PATH中:
为了解更多关于GOPATH环境变量,查看go help gopath。
为了使用客户化后的工作区的位置,设置GOPATH环境变量。
导入路径
import path是唯一标识包的字符串。一个包的导入路径对应工作区内或者远程代码库(下面解释)的位置。
标准函数包的包名以缩写形式给出,如fmt或net/http。至于你自己的包,你必须选择一个不和未来会增加的标准函数包或其它外部函数包冲突的基本路径。
如果你将代码保存在源码库的某个地方,你必须使用源码库的根作为基本路径。例如,如果你有个Github账户在github.com/user,那应该是你的基本路径。
注意在你可以编译前不需要将代码发布到远程代码库中。它只是一个管理代码的好习惯。实际上你可以任意选择路径名,只要对标准函数包来说是独一无二的。
我们将使用github.com/user作为基本路径。在工作区中创建目录存放代码:
第一个程序
为了编译和运行一个简单程序,首先选择包路径(github.com/user/hello)然后创建对应的包目录。
下一步,在目录中创建命名为hello.go文件,包含以下代码:
现在你可以使用go工具构建和安装这个程序。
注意,你可以在系统任意地方执行该命令。go工具通过查询github.com/user/hello来找到源码。
如果你从包目录中运行go install,你也可以忽略包路径:
这个命令构建了hello命令,产生一个可执行二进制文件。然后将名为hello的二进制文件安装到工作区的bin目录下。在我们的例子中,这个文件是$GOPATH/bin/hello,即$HOME/work/bin/hello。
go工具只会在报错时打印输出,因此如果这些命令没有输出就说明执行成功了。
你现在可以通过输入命令全路径运行程序:
或者,因为你将$GOPATH/bin加到PATH中了,只需要输入二进制文件名:
如果你正在使用一个源码控制系统,现在正好来初始化一个仓库,添加文件,提交第一个变更。再次说明,这步是可选的:你不需要使用源码控制来写Go代码。
将代码推送到远程仓库留给读者作为练习。
第一个函数包
让我们写一个函数包,并在hello程序中使用它。
再次,第一步是选择一个包路径(我们将使用github.com/user/stringutil)创建包目录:
接下来,在目录中创建reverse.go文件,内容如下:
现在,使用go build编译测试该包:
如果,你正位于包的源码目录,只需:
这不会产生输出文件。为此,你必须使用go install,这将包对象放到pkg目录中。
确认stringutil包构建后,修改原始的hello.go(在$GOPATH/src/github.com/user/hello中)以便使用:
无论什么时候go工具安装一个包或者二进制,它也会安装所有依赖。因此当你安装hello程序:
stringutil包也会被自动安装。
运行新版本程序,你应该会看到新的反转信息:
上述步骤以后,你的工作区看起来应该是这样:
注意,go install将stringutil.a对象放到pkg/linux_amd64下映射源目录的一个目录中。
因此go工具的后续引用可以找到这个包对象并避免不必要的重编译。linux_amd64部分帮助交叉编译,反映了操作系统和体系结构。
Go命令执行是静态链接的,Go程序的运行不需要包对象存在。
包名
Go源文件的第一条语句必须是
name 是包用于导入的默认名字。(包中所有文件必须使用相同的 name 。)
Go规范中包名是导入路径的最后一个元素: 导入为”crypto/rot13”的包名应该是 rot13 。
可执行命令必须总是使用 package main。
不需要连接到单个二进制文件的所有包名必须唯一,只要导入路径唯一就行。
查看 Effective Go来学习更多关于Go的命名规范。
测试
Go有一个由go test命令和testing包组成的轻量测试框架。
通过创建一个以_test.go结尾的文件来写测试案例,该文件包含具有func (t *testing.T)签名的以TestXXX命名的
函数。测试框架运行每个这样的函数;如果函数调用如t.Error或t.Fail的失败函数,测试被认为失败了。
创建包含以下Go代码的$GOPATH/src/github.com/user/stringutil/reverse_test.go文件,增加测试到stringutil包中。
然后使用go test运行测试:
一如既往,如果你在包目录里运行go工具,你可以忽略包路径:
运行go help test和查看testing package documentation获取更详细内容。
远程包
导入路径可以描述如何获取使用版本控制系统如Git或Mercuiral的包源码。go工具使用这个特性来自动获取远程仓库的包。例如,本文描述的案例同样保存在Github github.com/golang/example的Git仓库中。如果你在包导入路径中
包含仓库URL,go test将会自动获取、构建和安装。
如果指定包不在工作区中,go test会将其放到GOPATH指定的第一个工作区中。(如果包已存在,go get跳过远程获取,只执行go install同样的操作。)
执行上述go get命令之后,工作区目录应该看起来像这样:
Github上的hello命令依赖于相同仓库下的stringutil包。hello.go文件中的导入使用相同的
导入路径规范,因此go get命令也可以定位和安装依赖包:
这个规范是最简单地使你的Go包能被他人使用的方法。Go Wiki和
godoc.org提供了外部Go项目列表
下一步
订阅 golang-announce 邮件列表获取新版本Go发布时的通知。
查看 Effective Go 获取写出清爽、符合习惯的Go代码提示。
参加 A Tour of Go完全学习语言。
访问 documentation page 阅读关于Go语言和函数包工具的深度文章。
获取帮助
获取实时帮助,求助 Freenode IRC服务上#go-nuts中的有帮助的go程序员。
讨论Go语言的官方邮件列表是Go Nuts。
使用Go issue tracker反馈bug。