本文演示了一个简单的Go语言包的开发,以及 go tool
命令的使用,包含:获取、构建、安装Go包和命令的标准方法。php
go tool
要求用特别的方式来组织你的Go代码。仔细阅读本文,它解释了启动和运行Go安装的最简单方法。html
请注意,这与其余编程环境不一样,在这些环境中,每一个项目都有一个单独的工做区,工做区与版本控制仓库紧密相关。git
工做空间是一个目录层次结构,其根目录有两个目录:程序员
src
用于存放Go原文件bin
存放可执行的命令go工具构建二进制文件并将其安装到 bin
目录。github
src
子目录一般包含多个版本控制的仓库(例如Git),用于跟踪一个或多个源包的开发。golang
在实践中,工做区应该是什么样子呢? 下面给出一个例子:编程
bin/ hello # command executable outyet # command executable src/ 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
包和 一些其余的包。vim
一般工做区会包含不少的源仓库(包含须要多和命令)。大多数的Go开发者都会把他们的源代码和依赖存放在一个工做区。windows
命令和库是从不一样类型的源包构建的。咱们稍后会讨论这种区别。缓存
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
要编译和运行一个简单的程序,首先要选择一个包路径(咱们会使用 github.com/user/hello
),而后在工做区里建立一个相应的包目录:
$ mkdir $GOPATH/src/github.com/user/hello
接下来,在hello目录里建立一个 hello.go
文件,写入如下内容:
package main import "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/hello Hello, world.
若是已经把 $GOPATH/bin
加入到了 PATH
, 能够直接输入二进制文件名:
$ hello Hello, world.
若是你正在使用一个版本控制系统,好比Git,如今是时候来初始化来生成一个仓库(repository),而后添加文件,作第一次提交。
固然这一步是可选的,不必定非要使用版本控制系统来写Go代码
$ cd $GOPATH/src/github.com/user/hello $ git init Initialized 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 main import ( "fmt" "github.com/user/stringutil" ) func main() { fmt.Println(stringutil.Reverse("!oG ,olleH")) }
再次安装
$ go install github.com/user/hello
执行:
$ hello Hello, Go!
经过上面的一些步骤后,如今咱们的结构是这样子的:
bin/ hello # command executable src/ 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 stringutil import "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/stringutil ok github.com/user/stringutil 0.165s
若是当前是在 go test github.com/user/stringutil
目录中,则直接执行:
$ go test ok 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/hello Hello, Go examples!
若是指定的包不在工做区, go get
将会经过 GOPATH
把它放到指定的工做区,若是包已经存在, go get
会跳过远程获取,其行为与 go install
相同。
上面 go get
以后的目录结构以下:
bin/ hello # command executable src/ 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://phpcasts.org/topics/47