转载

如何编写Go代码

官方原文: How to Write Go Code ,

根据最新官方文档翻译。翻译参考 wang_yb 的 如何写 go 代码 。

因为官方文档有更新,我根据新版本的文档重新进行了翻译。

本文演示如何开发一个简单的 go package, 以及 go tool 的使用方法,

即获取(fetch), 编译(build), 安装(install) go package 的标准方法和命令.

go tool 需要你按照一定的标准来组织代码. 请仔细阅读本文.

它介绍了用来构建和运行 Go 程序的最简单方法.

介绍本文的视频参照: https://www.youtube.com/watch?v=XCsL89YtqCs。

代码组织

工作区Workspace

go tool 是设计用来和公共仓库的开源代码一起工作的.

即使你不需要发布你的代码, go tool 的工作模型也同样适用于你.

Go 代码必须保存在 工作区 中, 工作区 就是一个特定的目录结构, 根目录下有如下3个目录:

  • src 目录: 存放 go 源码文件, 按 package 来组织 (一个 package 一个文件夹)
  • pkg 目录: 存放 package 对象
  • bin 目录: 存放可执行的命令command

go tool 编译 src 下的文件, 并将编译好的二进制文件分别放入 pkg 或者 bin 文件夹中.

src 目录可以包含多个 版本控制仓库(比如 Git 或 Mercurial), 用来管理代码的开发.

一个实际的工作区的目录结构如下:

bin/

hello # command executable

outyet # command executable

pkg/

linux_amd64/

github. com /golang/example/

stringutil. a # package object

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

这个工作区包含一个仓库( example ),由两个命令组成( hellooutyet ),以及一个库( stringutil )。

一个典型的工作区可能包含很多源码库,这些源码库包含着N多的 packagecommand 。大部分的Go程序员会将他们的源码和依赖放在一个单一的工作区中。

命令Command和库libraries由各种source package编译而来。我们稍后再介绍

GOPATH 环境变量

GOPATH 环境变量指向你的 工作区 的位置. 这是你开发 Go 代码时唯一需要设置的环境变量.

开始开发时, 创建 工作区 的文件夹, 并设置对应的 GOPATH 环境变量.

你的 工作区 可以是任意文件夹, 本文中使用的路径是 $HOME/work

注意 不要把 GOPATH 设置为 go 的安装路径. (另一种常用设置方式是设置 GOPATH=$HOME )

$ mkdir $HOME /work

$ export GOPATH= $HOME /work

为了方便编译出的命令的执行, 将上面的 bin 目录加入到 PATH:

$ export PATH= $PATH : $GOPATH /bin

想了解更多设置GOPATH 环境变量的知识,可以查看 go help gopath

Package路径

标准库中的 package 只要使用短路径即可, 比如 "fmt", "net/http"。

对于自己的 package, 必须选一个基本路径以防止以后和标准库, 或者其他第三方的库产生冲突。

如果你的代码保存在某个代码仓库, 那么就可以使用那个代码仓库的根目录作为你的 package 的基本路径。

比如, 你有个 github 的账户在 github.com/user , 就可以使用 github.com/user 作为你的基本路径。

注意在能够正确编译代码之前, 你并不需要发布你的代码到远程的代码仓库。

但是如果有一天你发布代码的话, 组织好你的代码是个好习惯。

实际上, 你可以使用任意的路径名称, 只要它在 go 标准库和庞大的 go 生态系统中是唯一的。

我们使用 "github.com/user" 作为基本路径, 然后在工作区中创建文件夹来保存代码:

$ mkdir -p $GOPATH /src/github.com/user

第一个 Go 程序

为了编译和运行一个简单的 GO 程序, 首先要确定 package 路径(这里使用 github.com/user/hello ),

并且在工作区中创建对应 package 文件夹.

$ mkdir $GOPATH /src/github.com/user/hello

下一步, 在上面文件夹中创建 hello.go 文件, 文件内容如下:

package main

import "fmt"

func main() {

fmt.Printf( "Hello, world./n" )

}

然后, 可以通过 go tool 来编译和安装上面的 hello 程序。

$ go install github.com/user/hello

注意你可以在任何路径下运行上述命令, go tool 会根据 GOPATH 环境变量来从工作区中查找 github.com/user/hello。

如果在 package 所在文件夹中运行 go install, 也可以省略 package 路径。

$ cd $GOPATH /src/github.com/user/hello

$ go install

上面的命令编译了 hello 命令, 并产生此命令的二进制可执行文件。

然后将二进制文件 hello 安装到了 工作区 的 bin 文件夹下(Windows 下是 hello.exe)

在我们的例子中, 就是 $GOPATH/bin/hello, 即 $HOME/work/bin/hello。

go tool 只有在出错时才会输出信息, 如果上面的 go 命令没有输出就说明执行成功了.然后, 就可以在命令行中运行这个命令了.

$ $GOPATH /bin/hello

Hello, world.

或者, 如果你将 $GOPATH/bin 加入到 PATH 中了的话, 也可以执行执行 hello 命令。

$ hello

如果你使用了代码版本管理工具, 正好可以初始化你的仓库, 添加文件, 并 commit 你的第一个改变。当然这个步骤是可选的, 写 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) 0 b4507d] initial commit

1 file changed, 1 insertion(+)

create mode 100644 hello.go

你可以把发布这个仓库作为练习题。

第一个Go库

让我们来写一个库, 并将之用于上面的 hello 程序中.同样, 首先确定 package 路径 (这里使用 github.com/user/stringutil), 并创建对应的文件夹。

$ mkdir $GOPATH /src/github.com/user/stringutil

接着, 创建文件 reverse.go , 内容如下:

package stringutil

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 来编译此 package:

$ go build github.com/user/stringutil

或者在 package 的目录下, 直接运行 go build

$ go build

上面的命令不会产生输出文件。 为了生成输出文件, 必须使用 go install 命令, 它会在 pkg 文件夹下生成 package 对象.

stringutil package 编译成功之后, 修改之前的 hello.go 文件:

package main

import (

"fmt"

"github.com/user/stringutil"

)

func main() {

fmt.Printf(stringutil.Reverse( "!oG ,olleH" ))

}

无论用 go tool 安装 package 对象还是 二进制文件, 它都会安装所有的依赖.所以当你安装 hello 程序时,

$ go install github.com/user/hello

stringutil package 也会被自动安装.

运行新的 hello 程序, 可以看到如下输出:

$ hello
Hello, Go!

经过上面的步骤, 你的 工作区应该像下面这样:

bin/

hello # command executable

pkg/

linux_amd64/ # this will reflect your OS and architecture

github. com /user/

stringutil. a # package object

src/

github. com /user/

hello/

hello. go # command source

stringutil/

reverse . go # package source

注意go install 将 stringutil.a 放进了 pkg/linux_amd64 文件夹下与源码对应的目录中。

以后, go tool 就可以找到这个 package, 从而判断是否需要重新编译。

linux_amd64 是表示当前使用的系统, 它的目的是为了区分交叉编译出的其他平台的 package。

Go 编译出的二进制文件都是静态链接的, 所以上面的 bin/hello 在执行时并不需要 linux_amd64/go-files/stringutil.a 文件。

Package name

go 代码文件的第一行必须是:

package name

这里的 name 作为 package 的默认名称, 让其他 package import 的时候用.(同个 package 中的所有文件必须使用相同的 name)。

Go 约定 package name 是 import path 中最后一部分。

也就是说, 如果一个 package 被引用时写成 "crypto/rot13", 那么这个 package 的 name 就是 rot13。

编译为可执行文件的代码的 package name 必须是 main。

连接进同一个二进制文件的package name 不一定要唯一, 只要 pakage 的 import path 是唯一的就行。也就是上面的 crypto/rot13 必须唯一, 但是可以有 another-crypto/rot13。

Go 的命名规则可以参考: [Effective Go]( http://golang.org/doc/effective_go.html#names)

测试

Go 中包含一个轻量级的测试框架, 由 go test 命令和 testing package 组成。

测试文件的名称以 _test.go 结尾, 其中包含格式如 func TestXXXX(t *testing.T) 的函数。

测试框架会执行每个这样的函数, 如果函数中调用了 t.Error 或者 t.Fail , 就认为测试失败。

给上面的 package stringutil 增加测试文件, 路径: $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 github.com/user/stringutil

ok github.com/user/stringutil 0.165 s

或者进入到 package stringutil 的目录中后, 直接运行:

$ go test

ok github.com/user/stringutil 0.165 s

通过 go help test 或者 http://golang.org/pkg/testing/ 来进一步 GO 的测试框架。

远程 package

Go 的 import path 指示如何从版本管理系统(Git 或者 Mercurial) 中获取 package 的源码。go tool 可以利用这个特性来自动获取远程仓库的代码。

比如, 下面的例子中使用的代码同时也保存在 github 上( http://github.com/golang/example)。

如果你在代码中 import 了上面这个远程的 package, 那么 go get 命令会自动 获取, 编译, 安装这个 package。

$ go get github.com/golang/example/hello

$ $GOPATH /bin/hello

Hello, Go examples!

如果工作区中没有指定的 package, go get 命令会把这个 package 下载到 GOPATH 中定义的第一个工作区中。

(如果这个package已经存在, go get 会跳过获取这一步,执行 go install 相同的行为)

上面的 go get 命令执行之后, 文件夹结构大致如下:

bin/

hello # command executable

pkg/

linux_amd64/

github. com /golang/example/

stringutil. a # package object

github. com /user/

stringutil. a # package object

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.com 上的 hello 程序依赖同一个仓库中的 package stringutil,即 github.com 上的 hello.go 中引用了 github.com 上的 package stringutil, 所以, go get 命令也下载, 编译, 安装了 stringutil 模块。

import "github.com/golang/example/stringutil"

这个特性可以让你的 go package 很容易的被别人使用.

Go Wiki 和 godoc.org 上列出了很多第三方 Go 工程。

关于使用 go tool 来使用远程仓库的更多信息, 请参考: go help importpath

下一步

  • 订阅 golang-announce 邮件列表来了解最新的 Go release 信息
  • 将 Effective Go 作为参考资料来编写整洁, 地道的 Go 代码
  • 通过 A Tour of Go 来完成一次 go 的旅行
  • 访问 documentation page 来了解一系列关于Go语言的有深度的文章, 以及 Go 库和工具.

寻求帮助

  • 寻求实时帮助, 可以使用 FreeNode 的IRC server #go-nuts
  • Go 语言官方邮件列表 Go Nuts
  • 汇报 Go 语言的 bug 请使用 Go issue tracker
正文到此结束
Loading...