1 介绍

  • Introduction - 官方文档
  • 这篇文章简单介绍一个简单的Go包开发,并介绍go工具,获取、构建和安装Go包和命令的标准方法。
  • go tool要你详细地组织你的代码。仔细阅读这个文档。它解释了启动和运行Go安装的最简单方法。
  • 类似的解释可用作截屏视频

2 组织代码

2.1 概述

  • Overview - 官方文档
  • Go程序员一贯把他们的Go代码保持在单个工作区中
  • 一个工作区包括多个版本控制库(用Git管理)
  • 每个库包括一个或多个包
  • 每个包有一个或多个源文件在单个目录中
  • 引用路径由包的目录路径决定

  请注意,这与其他编程环境不同,在这些环境中,每个项目都有一个单独的工作区,工作区与版本控制存储库紧密相关。

2.2 工作区

  • Workspaces - 官方文档
  • 工作区是一个目录层级,它的根目录包括两个目录:
    • src包含Go的源码文件
    • bin包含可执行命令

  go tool构建和安装二进制到bin目录。

  src子目录一般包含多个版本控制库(比如Git和Mercurial)可以追踪开发的一个或多个源码包。

  比如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
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) ...

  上面的tree显示工作区包含两个库(example和image)。example库包含两个命令(hello和outyet)和一个二进制(stringutil)。image库包含bmp包和一些其他的。

  一般工作区包含一些源码库包含一些包和命令。大部分Go程序员保持所有的Go源码文件和依赖库在单个工作区。

  请注意,不应使用符号链接将文件或目录链接到工作区。

  命令和库是从不同类型的源包构建的。 我们稍后会讨论这种区别。

2.3 GOPATH环境变量

  • The GOPATH environment variable - 官方文档
  • GOPATH环境变量的具体说明你的工作区位置。它默认是home目录下面的go文件夹,$HOME/go在Unix上,$home/go Plan 9上,%USERPROFILE%\go在windows上。
  • 如果想工作在不同的位置,你需要设置GOPATH指向那个目录。注意GOPATH和go的安装目录不要重合。
  • go命令go env GOPATH打印有效的当前GOPATH;如果没有设置环境变量,就打印默认位置。
  • 为了方便,添加GOPATH的bin目录到环境变量PATH
1
export PATH=$PATH:$(go env GOPATH)/bin
  • 这个脚本设置后可以使用更简单的命令$GOPATH代替go env GOPATH。为了使脚本运行,如果你没设置GOPATH,你可以代替$HOME/go在这些命令中或者运行:
1
export GOPATH=$(go env GOPATH)
  • 更多的GOPATH环境变量,用命令查看go help gopath
  • 设置自定义的GOPATH,可以访问SettingGOPATH

2.4 导入路径

  • Import paths - 官方文档
  • 一个import paths是引入一个包,它有独一无二的标识符。一个包引入的路径是和工作区或者远端库相符合的。
  • 标准库的包引入的包使用的短路径比如fmtnet/http。对于你的包,你必须选择一个和将来添加的标准库或者其他额外的包路径不相同的路径。
  • 如果将代码保存在某个源存储库中,则应使用该源存储库的根作为基本路径。 例如,如果您在github.com/user上有一个GitHub帐户,那么这应该是您的基本路径。
  • 请注意,在构建代码之前,无需将代码发布到远程存储库。 组织代码只是一个好习惯,好像有一天你会发布它一样。 实际上,您可以选择任意路径名称,只要它对标准库和更大的Go生态系统是唯一的。
  • 我们将使用github.com/user作为我们的基本路径。 在工作区内创建一个目录,用于保存源代码:
1
mkdir -p $GOPATH/src/github.com/user

2.5 你的第一个程序

  • Your first program - 官方文档
  • 要编译和运行一个简单的程序,首先选择一个包路径(我们将使用github.com/user/hello)并在工作区内创建一个相应的包目录:
1
$ mkdir $GOPATH/src/github.com/user/hello
  • 接下来,在该目录中创建一个名为hello.go的文件,其中包含以下Go代码。
1
2
3
4
5
6
7
package main

import "fmt"

func main() {
	fmt.Println("Hello, world.")
}
  • 现在,您可以使用go工具构建和安装该程序:
1
$ go install github.com/user/hello
  • 请注意,您可以从系统的任何位置运行此命令。 go工具通过在GOPATH指定的工作空间内查找github.com/user/hello包来查找源代码。
  • 如果从包目录运行go install,也可以省略包路径:
1
2
$ cd $GOPATH/src/github.com/user/hello
$ go install
  • 此命令构建hello命令,生成可执行二进制文件。 然后,它将该二进制文件作为hello(或在Windows下,hello.exe)安装到工作空间的bin目录中。 在我们的示例中,这将是$ GOPATH / bin / hello,即$ HOME / go / bin / hello。
  • go工具仅在发生错误时打印输出,因此如果这些命令不产生输出,则它们已成功执行。
  • 您现在可以通过在命令行键入其完整路径来运行该程序:
1
2
$ $GOPATH/bin/hello
Hello, world.
  • 或者,正如您已将$ GOPATH / bin添加到PATH中,只需键入二进制名称:
1
2
$ hello
Hello, world.
  • 如果您正在使用源代码控制系统,那么现在是初始化存储库,添加文件和提交第一个更改的好时机。 同样,此步骤是可选的:您不需要使用源代码控制来编写Go代码。
1
2
3
4
5
6
7
8
$ 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
  • 将代码推送到远程存储库留给读者练习。

2.6 你的第一个库

  • Your first library - 官方文档
  • 让我们编写一个库并从hello程序中使用它。
  • 同样,第一步是选择一个包路径(我们将使用github.com/user/stringutil)并创建包目录:
1
$ mkdir $GOPATH/src/github.com/user/stringutil
  • 接下来,使用以下内容在该目录中创建名为reverse.go的文件。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 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编译:
1
$ go build github.com/user/stringutil
  • 或者,如果您在包的源目录中工作,只需:
1
$ go build
  • 这不会产生输出文件。 相反,它将已编译的包保存在本地构建缓存中。
  • 在确认stringutil包构建之后,修改原始的hello.go(在$ GOPATH/src/github.com/user/hello中)以使用它:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package main

import (
	"fmt"

	"github.com/user/stringutil"
)

func main() {
	fmt.Println(stringutil.Reverse("!oG ,olleH"))
}
  • 安装hello程序:
1
$ go install github.com/user/hello
  • 运行新版本的程序,您应该看到一条新的反向消息:
1
2
$ hello
Hello, Go!
  • 完成上述步骤后,您的工作区应如下所示:
1
2
3
4
5
6
7
8
bin/
    hello                 # command executable
src/
    github.com/user/
        hello/
            hello.go      # command source
        stringutil/
            reverse.go    # package source

2.7 包名

1
package name
  • 其中name是包的默认名称。(包中的所有文件必须使用相同的名称。)
  • Go的约定是包名称是导入路径的最后一个元素:导入为“crypto/rot13”的包应命名为rot13。
  • 可执行命令必须始终使用package main。
  • 不要求包名称在链接到单个二进制文件的所有包中都是唯一的,只要导入路径(它们的完整文件名)是唯一的。
  • 请 参阅Effective Go以了解有关Go的命名约定的更多信息。

3 Testing

  • Testing - 官方文档
  • Go有一个由go test命令和测试包组成的轻量级测试框架。
  • 您通过创建名称以_test.go结尾的文件来编写测试,该文件包含名为TestXXX且带有签名func(t * testing.T)的函数。 测试框架运行每个这样的功能; 如果函数调用失败函数(如t.Error或t.Fail),则认为测试失败。
  • 通过创建包含以下Go代码的文件 $GOPATH/src/github.com/user/stringutil/reverse_test.go,将测试添加到stringutil包中。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
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测试运行测试:
1
2
$ go test github.com/user/stringutil
ok  	github.com/user/stringutil 0.165s
  • 与往常一样,如果从包目录运行go工具,则可以省略包路径:
1
2
$ go test
ok  	github.com/user/stringutil 0.165s

4 远端包

  • Remote packages - 官方文档
  • 导入路径可以描述如何使用诸如Git或Mercurial之类的修订控制系统来获取包源代码。 go工具使用此属性自动从远程存储库获取包。
  • 例如,本文档中描述的示例也保存在GitHub github.com/golang/example上托管的Git存储库中。 如果在包的导入路径中包含存储库URL,则get将自动获取,构建和安装它:
1
2
3
$ go get github.com/golang/example/hello
$ $GOPATH/bin/hello
Hello, Go examples!
  • 如果工作空间中不存在指定的包,则get将其放在GOPATH指定的第一个工作空间内。 (如果包已经存在,请跳过远程提取,其行为与go install相同。)
  • 发出上面的go get命令后,工作区目录树现在应如下所示:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
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命令也能够找到并安装依赖包。
1
import "github.com/golang/example/stringutil"
  • 此约定是让其他人可以使用Go包的最简单方法。 Go Wikigodoc.org提供了外部Go项目的列表。
  • 有关使用go工具使用远程存储库的更多信息,请参阅go help importpath

5 下一步

6 获取帮助