简介本文演示了一个简单的Go语言包的开发,以及 go tool 命令的使用,包含:获取、构建、安装Go包和命令的标准方法。go tool 要求用特别的方式来组织你的Go代码。仔细阅读本文,它解释了启动和运行Go安装的最简单方法。代码组织概述程序员通常会将所有Go代码保存在一个工作区中工作空间包含许多版本控制的仓库(repo)(例如,由Git管理的)每个仓库包含一个或多个包每个包由一个目录中的一个或多个Go源文件组成包目录的路径确定其导入路径请注意,这与其他编程环境不同,在这些环境中,每个项目都有一个单独的工作区,工作区与版本控制仓库紧密相关。工作区工作空间是一个目录层次结构,其根目录有两个目录:src 用于存放Go原文件bin 存放可执行的命令go工具构建二进制文件并将其安装到 bin 目录。src 子目录通常包含多个版本控制的仓库(例如Git),用于跟踪一个或多个源包的开发。在实践中,工作区应该是什么样子呢? 下面给出一个例子:bin/ hello # command executable outyet # command executablesrc/ github.com/golang/example/ .git/ # Git repository metadata hello/ hello.go # command source outyet/ main.go # command source main_test.go # test source stringutil/ reverse.go # package source reverse_test.go # test source golang.org/x/image/ .git/ # Git repository metadata bmp/ reader.go # package source writer.go # package source … (many more repositories and packages omitted) …上面的这个树型结构展示出一个工作区包含了2个仓库(example 和 image)。example 仓库包含了2个命令(hello 和 outyet)和一个库(stringutil)。image 仓库包含了 bmp 包和 一些其他的包。通常工作区会包含很多的源仓库(包含需要多和命令)。大多数的Go开发者都会把他们的源代码和依赖存放在一个工作区。命令和库是从不同类型的源包构建的。我们稍后会讨论这种区别。GOPATH 环境变量GOPATH 环境变量用来指定工作区的位置。默认是用户主目录的 go 目录,如在Linux和macOS上是 $HOME/go, 在Windows上是 C:\Users\YourName\go。go env GOPATH 命令会打印出当前有效的 GOPATH; 如果环境变量没有被设置会打印出默认的位置。为方便起见,将工作空间的 bin 子目录添加到 PATH:$ export PATH=$PATH:$(go env GOPATH)/bin为简洁起见,本文档其余部分中的脚本使用 $GOPATH 而不是 $(go env GOPATH)。即$ export PATH=$PATH:$GOPATH/bin而如果还没有设置 $GOPATH 就运行写好的脚本,你需要替换为 $HOME/go, 否则需要执行:$ export GOPATH=$(go env GOPATH)要学习更多关于gopath环境变量,可以使用查看帮助 go help gopath要使用自定义的工作区,可以查看 https://golang.org/wiki/SettingGOPATH导入路径导入路径(import path)是唯一标识包的字符串。包的导入路径对应于其在工作空间内或远程仓库中的位置(如下所述)。标准库中的包具有简短的导入路径,例如 fmt 和 net/http。对于我们自己开发的包您必须选择一个基本路径,该路径不太可能与将来添加到标准库或其他外部库中发生冲突。如果将代码保存在某个源仓库中,则应使用该源仓库的根作为基本路径。例如,如果你在 github.com/user 上有一个GitHub帐户,那么这应该是你的基本路径。请注意,在构建代码之前,无需将代码发布到远程仓库。组织代码只是一个好习惯,好像有一天你会发布它一样。实际上,你可以选择任意路径名称,只要它对标准库和更大的Go生态系统是唯一的。我们将使用 github.com/user 作为我们的基本路径。在工作区内创建一个目录,用于保存源代码:$ mkdir -p $GOPATH/src/github.com/user你的第一个Go程序要编译和运行一个简单的程序,首先要选择一个包路径(我们会使用 github.com/user/hello),然后在工作区里创建一个相应的包目录:$ mkdir $GOPATH/src/github.com/user/hello接下来,在hello目录里创建一个 hello.go 文件,写入以下内容:package mainimport “fmt"func main() { fmt.Println(“Hello, world.”)}现在就可以使用go工具来构建和安装该程序:go install github.com/user/hello注意,你可以在系统上的任何地方运行该命令。go工具通过在 GOPATH 指定的工作空间内查找 github.com/user/hello 包来查找源代码。如果是在这个包目录内运行 go install 也可以忽略包路径:$ cd $GOPATH/src/github.com/user/hello$ go install该命令会生成一个 hello 命令,生成一个可执行的二进制文件。同时安装到工作区目录下的 bin 目录,生成的可执行文件是 hello(如果是windows则是 hello.exe)。在本例子中是 $GOPATH/bin/hello, 也就是 $HOME/go/bin/hello。当有错误发生的时候,go工具仅会打印除错误,所以如果没有任何输出的时候说明已经执行成功。可以通过全路径来运行:$ $GOPATH/bin/helloHello, world.如果已经把 $GOPATH/bin 加入到了 PATH, 可以直接输入二进制文件名:$ helloHello, world.如果你正在使用一个版本控制系统,比如Git,现在是时候来初始化来生成一个仓库(repository),然后添加文件,做第一次提交。当然这一步是可选的,不一定非要使用版本控制系统来写Go代码$ cd $GOPATH/src/github.com/user/hello$ git initInitialized empty Git repository in /home/user/work/src/github.com/user/hello/.git/$ git add hello.go$ git commit -m “initial commit”[master (root-commit) 0b4507d] initial commit 1 file changed, 1 insertion(+) create mode 100644 hello.go$ git push origin master 你的第一个库我们再来写一个库,并在 hello 程序中使用。首先,第一步确定好包路径,我们使用 github.com/user/stringutil, 创建包目录$ mkdir $GOPATH/src/github.com/user/stringutil其次,创建一个名为 reverse.go 的文件,并写入以下内容:// Package stringutil contains utility functions for working with strings.package stringutil// Reverse returns its argument string reversed rune-wise left to right.func Reverse(s string) string { r := []rune(s) for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { r[i], r[j] = r[j], r[i] } return string(r)}使用 go build 编译该包:$ go build github.com/user/stringutil如果已经在 github.com/user/stringutil 目录里,则直接执行:$ go build当然该命令不会生成文件,而是把编译好的包放到了本地的构建(build)缓存里。确实 stringutil 包被编译后, 修改 hello.go:vim $GOPATH/src/github.com/user/hello修改后的:package mainimport ( “fmt” “github.com/user/stringutil”)func main() { fmt.Println(stringutil.Reverse("!oG ,olleH”))}再次安装$ go install github.com/user/hello执行:$ helloHello, Go!通过上面的一些步骤后,现在我们的结构是这样子的:bin/ hello # command executablesrc/ github.com/user/ hello/ hello.go # command source stringutil/ reverse.go # package source包名在Go原文件中第一个使用的语句必须是package name其中 name 就是包的默认名称。一个包中的所有文件必须使用相同的包名。Go的约定是包名称是导入路径的最后一个元素,例如导入的包 crypto/rot13, 包名就是 rot13如果是可执行的文件,包名必须使用 main。不强制要求所有的包名都是唯一的,但是要求导入的路径必须是唯一的(全路径文件名)。更多关于go的命名规范可以查看 Effective Go测试Go提供了一个由 go test 和 testing 包组成的测试框架。通过创建一个以 _test.go 结尾的文件,里面写有以 TestXXX 开头的函数。测试框架会运行每一个这样的函数,如果函数调用了一个失败的函数,如 t.Error 或 t.Error, 那么测试就算不通过。通过添加一个测试文件到 stringutil 包中,$ vim $GOPATH/src/github.com/user/stringutil/reverse_test.go添加如下代码:package stringutilimport “testing"func TestReverse(t *testing.T) { cases := []struct { in, want string }{ {“Hello, world”, “dlrow ,olleH”}, {“Hello, 世界”, “界世 ,olleH”}, {”", “”}, } for _, c := range cases { got := Reverse(c.in) if got != c.want { t.Errorf(“Reverse(%q) == %q, want %q”, c.in, got, c.want) } }}然后运行测试 go test:$ go test github.com/user/stringutilok github.com/user/stringutil 0.165s如果当前是在 go test github.com/user/stringutil 目录中,则直接执行:$ go testok github.com/user/stringutil 0.165s更多细节可以运行 go run test 和 查看 测试包文档远程包导入路径可以描述如何使用诸如Git之类的版本控制系统来获取包源代码。go工具使用此属性自动从远程仓库获取包。例如,本文档中描述的示例也保存在GitHub github.com/golang/example 上托管的Git仓库中。如果你在包的导入路径中包含仓库URL,那么go将自动获取,构建和安装它:$ go get github.com/golang/example/hello$ $GOPATH/bin/helloHello, Go examples!如果指定的包不在工作区, go get 将会通过 GOPATH 把它放到指定的工作区,如果包已经存在, go get 会跳过远程获取,其行为与 go install 相同。 上面 go get 之后的目录结构如下:bin/ hello # command executablesrc/ github.com/golang/example/ .git/ # Git repository metadata hello/ hello.go # command source stringutil/ reverse.go # package source reverse_test.go # test source github.com/user/ hello/ hello.go # command source stringutil/ reverse.go # package source reverse_test.go # test source在GitHub上托管的 hello 命令取决于同一仓库中的 stringutil 包。 hello.go 文件中的导入使用相同的导入路径约定,因此 go get 命令也能够找到并安装依赖包。import “github.com/golang/example/stringutil"此约定是使你的Go包可供其他人使用的最简单方法。Go Wiki和godoc.org提供了外部Go项目的列表。有关使用go工具使用远程仓库的更多信息, 可以查看 go help importpath原文地址:https://golang.org/doc/code.html