预览
- Go程序员通常让所有的Go代码在一个单独的工作空间(workspace).
- 一个工作空间包含很多版本控制仓库(比如,通过git管理)
- 每个仓库包含一个或者多个包(packages).
- 每个包由单独的目录下的Go源文件组成.
- 包的目录路径决定他的导入路径
注意这是和其他编程环境不同的地方:每个项目都有单独的工作空间,并且工作空间与版本控制仓库紧密绑定
工作空间
工作根目录有两个目录:
- src包含够源文件
- bin包含可执行命令
go tool
构建并安装binaries到bin目录
src
子目录一般包含多个版本控制仓库(比如Git或者Mercurial)追踪一个或多个源包的开发。
下面展示工作空间的结构:
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) ...</pre>
上面的树显示工作空间包含两个仓库(example
和image
)。example
仓库包含两个命令(hello
和outyet
)和一把库(stringutil
). image
仓库包含bmp
包和其他的一些内容
经典的工作空间包含多个源仓库,源仓库包含多个包和命令。大多数的Go程序员将所有的Go源代码和依赖放在一个单独的工作空间。
注意,不应该使用symbolic links关联文件或者目录到工作空间。
GOPATH环境变量
GOPATH环境变量指定工作空间的位置。默认是在home目录里的go目录,比如Unix的$HOME/go
,Windows的%USERPROFILE%\go
(通常是C:\Users\YourName\go
)。
如果想在不同的地方,可以使用set GOPATH
指定目录的路径。(另一种通用的设置是GOPATH=$HOME).注意GOPATH一定不能是Go的安装目录。
go env
命令打印当前有效的GOPATH,如果没有设置则打印默认的位置。
为了方便,添加工作空间的bin目录到你的路径:
$ export PATH=$PATH:$(go env GOPATH)/bin
为了简短,接下来的文档使用(go env GOPATH)。
导入路径(Import paths)
import path
是唯一的字符串表示包。包的导入路径对应工作空间里它的位置或者远程仓库位置。
标准库里的包具有简短的导入路径,比如fmt
和net/http
。对于你自己的包,指定的路径不能与标准库里的包或者其他内部包冲突。
如果你将代码保存在源文件仓库,那么应该使用源仓库的根目录作为你的基础路径。比如,如果你有Github
账号,那么github.com/{user}
就是你的基本路径。
注意不要再你能构建之前推送代码到远程仓库。
我们将使用github.com/{user}
作为你的基础路径。在工作空间下创建一个目录保存源代码:
$ mkdir -p $GOPATH/src/github.com/user
第一个程序
要编译和运行一个简单的程序,先选择一个包路径(我们先用github.com/user/hello)并且在工作空间创建相应的包目录:
$ mkdir $GOPATH/src/github.com/user/hello
接下来,在这个目录下创建一个名为hello.go
的文件,包含如下代码:
package main
import "fmt"
func main() {
fmt.Println("Hello, world.")
}
现在就可以构建并安装程序了:
$ go install github.com/user/hello
现在你就可以在你的系统里运行这个命令了。go tool
通过GOPATH指定的工作空间查找github.com/user/hello
包的源代码
如果已经在包目录里,就可以省略掉包路径
$ cd $GOPATH/src/github.com/user/hello
$ go install
这个命令构建hello
命令,产生一个可执行的binary。然后安装这个binary到工作空间下的bin目录,也就是$HOME/go/bin/hello
go tool
只会在有错误的时候打印输出,所以如果没有内容产生,表示执行成功。
现在可以通过全路径运行程序
$ $GOPATH/bin/hello
Hello, world.
第一个库
现在我们编写一个library并且在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
如果已经在包源目录下,只需要:
go build
这不会产生输出文件。而是将编译完的包保存到本地构建缓存里。
现在修改hello.go
来使用它:
package main
import (
"fmt"
"github.com/user/stringutil"
)
func main() {
fmt.Println(stringutil.Reverse("!oG, olleH"))
}
install hello
程序
$ go install github.com/user/hello
这一顿操作后,工作空间应该变成了:
bin/
hello # command executable
src/
github.com/user/
hello/
hello.go # command source
stringutil/
reverse.go # package source
Package names
Go源文件里的第一行一定是:
package name
其中name是包的默认名称。
(包中的所有文件必须使用相同的名称。)
Go的约定是报名是导入路径最后一个节点:crypto/rot13
的包名是rot13
可执行命令的包名必须是package main
。
不要求包名称在链接到单个二进制文件的所有包中都是唯一的,只要导入路径(它们的完整文件名)是唯一的。
测试
Go有一个由go test
命令和测试包组成的轻量级测试框架。
创建一个用_test.go
结尾的文件,里面的方法命名为TestXXX
。测试框架会运行每个方法;如果方法调用失败方法比如t.Error
或者t.Fail
,测试就被认为失败了。
创建一个$GOPATH/src/github.com/user/stringutil/reverse_test.go
文件测试stringutil
:
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
远程包
导入路径可以描述如何使用诸如Git或Mercurial之类的修订控制系统来获取包源代码。go tool使用该属性自动从远程仓库拉去包。比如,本文档里的实例就保存在github.com/golang/example
。如果你在包的导入路径引入远程URL, go get将会自动获取,构建并且安装它:
$ go get github.com/golang/example/hello
$ $GOPATH/bin/hello
Hello, Go examples!
如果工作空间不存在指定的包,go get
会将它放在GOPATH指定的第一个工作空间内。(如果包存在,go get
会跳过远程获取,就和go install
的行为一样了)
经过上面的操作后,工作目录结构将会变为:
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
Gihub上托管的hello
命令依赖同一仓库下的stringutil
包。hello.go
文件里的imports使用相同的导入路径规范,所以go get命令可以定位并且安装起来的包:
import "github.com/golang/exmaple/stringutil"
规范是最简单的方式让你的Go包可以对其他的可用