原文: http://golang.org/doc/code.html
介绍
本文档演示了一个简单Go package的开发并介绍了go命令,获取,构建和安装Go包和程序的标准方法.
代码组织
GOPATH 和工作区
Go的设计目标其中之一就是使得写软件更容易.为此,go命令不使用Makefile或者其他的配置文件来指导程序构建.它使用源代码来寻找依赖并决定构建条件.这意味着你的源代码和构建脚本总是同步的;它们是一个东西,是一回事.
你必须设置GOPATH环境.GOPATH告诉go命令(和一些其它相关工具)在你的系统里哪里可以找到和安装Go包.
GOPATH是一个路径列表.它和你系统PATH环境变量的语法一样.一个Unix系统下典型的GOPATH看起来像这个样子:
GOPATH=/home/user/ext:/home/user/mygo (Windows GOPATH=/home/user/ext;/home/user/mygo)
列表中的每一个路径/home/user/ext或者/home/user/mygo指定了工作区的位置.一个工作区包含了Go源代码和相关的包对象,可执行文件.按照约定有三个子目录的结构:
src 包含源代码
pkg 包含编译的包对象
bin 包含可执行文件
src目录的子目录们控制独立的包,所有在每个子目录中的源代码(.go.c .h .s)是子目录的包的组成元素
当构建一个import "widget"的程序时,go command在Go root内寻找src/pkg/widget,如果没有它就会按次序在每个工作区内寻找src/widget.
多个工作区更加灵活和方便,但现在我们只关心单个的工作区.
让我们完成一个简单的例子.首先,创建一个$HOME/mygo目录和它的src子目录:
$mkdir -p $HOME/mygo/src #新建一个地方放置源代码
然后,设置它为GOPATH.你应当添加bin子目录到你的PATH环境变量,这样你就可以不需要指定全路径就可以运行命令了. 为此添加下列行到$HOME/.profile(或者其它等价方法)
export GOPATH=$HOME/mygo export PATH=$PATH:$HOME/mygo/bin
导入路径
标准包为了方便只需要给定短路径例如"fmt"和"net/http".对于你自己的项目而言,选择一个不太可能和未来新增到标准库或者其它外部库冲突的基础导入路径是很重要的.
最好的办法是使用你版本控制仓库的位置选择导入路径.例如,如果你的源仓库是在example.com或者code.google.com/p/example,你应当用这个URL来开始你的包路径,如"example.com/foo/bar"或者"code.google.com/p/example/foo/bar".根据这个约定,gocommand能自动checkout并且单独通过导入路径构建源代码.
如果你不想用这种方法安装你的代码,你应当至少使用一个独一无二的前缀像"widgets/",如"widgets/foo/bar".一个好的规则是使用你的公司或者项目名,因为它不太可能被别人使用.
我们将使用example/作为基础导入路径:
$mkdir -p $GOPATH/src/example
包名
在一个Go源文件中的第一个声明应该是
package name
这儿name就是包的作为导入的默认名字.一个包中的所有文件都必须使用相同的name.
Go的约定是包名是导入路径的最后一个元素:如"crypto/rot13"这样导入的包应当命名rot13.没有必要让包名是通过的所有包链接成的单一二进制唯一标识.只要导入路径唯一即可.
在example下创建一个新包叫做newmath:
$ cd $GOPATH/src/example $ mkdir newmath
创建一个文件叫做$GOPATH/src/example/newmath/sqrt.go, 包含下列Go代码:
// 包newmath 是一个没什么价值的示例包. package newmath // Sqrt returns an approximation to thesquare root of x. func Sqrt(x float64) float64 { // This is a terribleimplementation. // Real code should import"math" and use math.Sqrt. z := 0.0 for i := 0; i < 1000; i++ { z -= (z*z - x) / (2 *x) } return z }
使用它所在的目录的路径名导入这个包,从src后面的成员开始.(译注:全路径是$GOPATH/src/example/newmath)
import "example/newmath"
参看Effective Go学习更多关于Go名字约定方面的内容.
构建和安装
go command 包含几个子命令,最重要的是install.运行go install importpath构建和安装一个包及它的依赖.
"install apackage"意味着写包对象或者可执行文件到源代码所在的工作区的pkg或者bin子目录。
构建一个包
构建和安装newmath包,键入
$ go install example/newmath
如果这个包和它的依赖已经构建和安装,这个命令将无任何输出.
为了方便,如果命令行没有指定导入路径,将默认当前目录.下面这些命令和上面的具有相同的效果:
$ cd $GOPATH/src/example/newmath $ go install
最后的工作区目录树(假定运行的是linux64位系统)就像下面这样:
pkg/
linux_amd64/
example/
newmath.a # packageobject
src/
example/
newmath/
sqrt.go # packagesource
构建应用程序
go command 把属于包main的代码看作可执行程序,然后安装包二进制文件到GOPATH的bin子目录。
添加一个叫做hello的程序到源树.首先创建example/hello目录:
$ cd $GOPATH/src/example $ mkdir hello
然后创建文件$GOPATH/src/example/hello/hello.go,包含下面的Go代码:
// Hello 是main包的一个无价值的例子. package main import ( "example/newmath" "fmt" ) func main() { fmt.Printf("Hello, world. Sqrt(2) = %v\n", newmath.Sqrt(2)) }
接下来运行goinstall,它会构建和安装二进制文件到$GOPATH/bin(或者$GOBIN,如果设置了的话;为了描述简化,这里假定GOBIN未设置)
$ go install example/hello
译注:hello是包名(目录名),而不是文件名.
像运行其它的命令一样,键入名字:
$ $GOPATH/bin/hello Hello, world. Sqrt(2) =1.414213562373095
如果你添加了$HOME/mygo/bin到你的PATH,你可以省略可执行文件的路径.
$ hello Hello, world. Sqrt(2) =1.414213562373095
工作区目录现在看起来是这样的:
bin/
hello # commandexecutable
pkg/
linux_amd64/
example/
newmath.a # packageobject
src/
example/
hello/
hello.go # commandsource
newmath/
sqrt.go # packagesource
go command 还提供build命令,有点像install,除了它构建所有对象在一个临时目录和不安装它们到pkg或bin下面外.构建一个可执行文件,导入路径的最后一个元素后的名字被写入当前目录.当构建一个包时,go build服务只是测试这个包和它的依赖能否被构建.(包对象结果总是会被丢弃)
测试
Go 有一个轻量级的测试框架,由go test命令和testing包组成。
通过创建一个以_test.go结尾的文件写一个测试,它包含命名为TestXXX的签名函数(t*testing.T). test框架测试每一个这样的函数;如果函数调用了一个函数失败比如t.Error或者t.Fail,测试被认为失败.
通过创建文件$GOPATH/src/example/newmath/sqrt_test.go添加一个测试到newmath包,包含下列代码:
package newmath import "testing" func TestSqrt(t *testing.T) { const in, out = 4, 2 if x := Sqrt(in); x != out { t.Errorf("Sqrt(%v) = %v, want%v", in, x, out) } }
现在用gotest运行测试:
$ go test example/newmath ok example/newmath 0.165s
更多详情请运行go help test并参看testing包文档.
远程包
一个导入路径可以描述为怎样使用修订版本的控制系统比如Git或者Mercurial获得包源代码.Go command利用这个特性来自动从远程仓库获取包.例如,这个文档的例子也保存在一个寄存在GoogleCode的Mercurial仓库,code.google.com/p/go.example.如果你在包的导入路径中包含仓库URL,go get将自动获取,构建,安装它:
$ go getcode.google.com/p/go.example/hello $ $GOPATH/bin/hello Hello, world. Sqrt(2) =1.414213562373095
如果指定的包不在一个工作区,go get将把它放在GOPATH中指定的第一个工作区.(如果包已经存在,go get 会跳过远程获取并做goinstall同样的事情.)
执行完上述goget命令,工作区目录树看起来是这样的:
bin/
hello # commandexecutable
pkg/
linux_amd64/
code.google.com/p/go.example/
newmath.a # packageobject
example/
newmath.a # packageobject
src/
code.google.com/p/go.example/
hello/
hello.go # commandsource
newmath/
sqrt.go # packagesource
sqrt_test.go # testsource
example/
hello/
hello.go # commandsource
newmath/
sqrt.go # packagesource
sqrt_test.go # testsource
hello程序寄存在GoogleCode依赖于在相同仓库内的newmath包. hello.go文件中的imports使用了相同的导入路径约定,这样goget命令也能够定位和安装依赖的包。
import"code.google.com/p/go.example/newmath"
这个约定是使得你的Go包为其他人可用的最简单的方法.Go community Wiki有一个包含程序和库的外部Go项目列表。
更多利用gocommand使用远程仓库的信息,参看gohelp remote.
译于2013.04.03 上海
有疑问加站长微信联系(非本文作者)