0
0

翻译-如何组织Go代码

smallfish 发表于 2014年11月06日 08:00 | Hits: 1768

原文地址:http://talks.golang.org/2014/organizeio.slide,译文尽量贴近原文,会适当的增删,勿拍。

Go 程序都是由包构成,每个文件都以package开头,程序主体执行从main包开始:

package main

import "fmt"

func main() {
        fmt.Println("Hello, world!")
}

最简单的一个 Go 程序,只需要写一个main包即可。

hello world第二行导入了fmt包,第四行Println是fmt包里的公开导出的函数。

示例包:fmt

// Package fmt implements formatted I/O.
package fmt

// Println formats using the default formats for its
// operands and writes to standard output.
func Println(a ...interface{}) (n int, err error) {
        ...
}

func newPrinter() *pp {
        ...
}

其中Println是公开(public)函数,只需要第一个字母大写,在其他模块内都是公开可见的(区别于私有private函数)。

另外一个函数newPrinter则是私有函数,以小写字母开头,这样的函数只能在模块(fmt)内使用。

通过包来组织和区分相关代码,包可大可小,也可以由多个文件构成,这些文件需要在一个目录内。

Go 源码net/http包导出 100 个命名(共 18 个文件),而errors包只导出 1 个名字(只有 1 文件)。

如何给包命名?

取名尽量简单和可阅读,不要使用下划线:

  • io/ioutil,不要用 io/util
  • suffixarray,不要用 suffix_array

也不要太笼统,比如util意思很模糊。

包名也是类型和函数的一部分,比如:

buf := new(bytes.Buffer)

这里不要取名为bytes.BytesBuffer,过于累赘。

选择一个好的命名真的很重要,大部分时候我们写代码都在为取名而烦恼啊。。。

包的测试

测试文件和源码同级目录,文件名都是_test.go结尾:

package fmt

import "testing"

var fmtTests = []fmtTest{
        {"%d", 12345, "12345"},
        {"%v", 12345, "12345"},
        {"%t", true, "true"},
}

func TestSprintf(t *testing.T) {
        for _, tt := range fmtTests {
            if s := Sprintf(tt.fmt, tt.val); s != tt.out {
                    t.Errorf("...")
            }
        }
}

差不多了,建议一个源码文件对应一个测试文件。

代码组织

工作目录(workspace)

新版 Go 依赖$GOPATH这个环境变量来区分工作目录。代码放在同一个workspace内,可以包含自己的包或远程仓库(如:git或hg),用过go get应该都知道。

Go 相关工具可以很容易的区分出工作空间,构建时候不需要依赖Makefile或build.xml类似文件 ,按照目录划分好就可以啦。

比如:

$GOPATH/
    src/
       github.com/user/repo/
           mypkg/
              mysrc1.go
              mysrc2.go
           cmd/mycmd/
                main.go
   bin/
       mycmd

这里示例一下工作目录吧

mkdir /tmp/gows
GOPATH=/tmp/gows

$GOPATH环境变量前面以及提到,后续的安装和构建包都依赖这个:

$ go get github.com/dsymonds/fixhub/cmd/fixhub

go get命令则会远程仓库下载源码到自己的工作目录内(需要相关的版本工具,比如:git)

go install命令则可以编译和分发文件到$GOPATH/bin/fixhub位置。

我的工作目录大概如下:

$GOPATH/
    bin/fixhub                              # installed binary
    pkg/darwin_amd64/                       # compiled archives
        code.google.com/p/goauth2/oauth.a
        github.com/...
    src/                                    # source repositories
        code.google.com/p/goauth2/
            .hg
            oauth                           # used by package go-github
            ...
        github.com/
            golang/lint/...                 # used by package fixhub
                .git
            google/go-github/...            # used by package fixhub
                .git
            dsymonds/fixhub/
                .git
                client.go
                cmd/fixhub/fixhub.go        # package main

可以看到下载了很多远程的仓库,编译后可执行文件是bin/fixhub。

为什么要划分目录结构呢?

通过目录结构来区分,可以免去配置的麻烦,不像其他语言会依赖Makefile或build.xml文件。

减少配置的时间,可以更多的时间去码字,另外大部分用户目录结构都类似,这样也更有利于去分享代码。

有时候我们可能有很多的工作目录,但是大部分人只用一个。有个建议这样来声明GOPATH:

GOPATH=$HOME

这样src,bin和pgk都会在你的用户home目录下了。

这里的建议应该是针对一台机器上多个用户来说吧,一般来说 ` $HOME/bin可能在PATH` 中了,调用起来更为方便一些。

快速切换目录

CDPATH=$GOPATH/src/github.com:$GOPATH/src/code.google.com/p

$ cd dsymonds/fixhub
/tmp/gows/src/github.com/dsymonds/fixhub
$ cd goauth2
/tmp/gows/src/code.google.com/p/goauth2
$

还可以写个函数放入到~/.profile内:

gocd () { cd `go list -f '' $1` }

这样移动更方便一些:

$ gocd .../lint
/tmp/gows/src/github.com/golang/lint
$

go工具有很多功能:

$ go help
Go is a tool for managing Go source code.

Usage:

go command [arguments]

The commands are:

常用的功能参数如:

build       compile packages and dependencies
get         download and install packages and dependencies
install     compile and install packages and dependencies
test        test packages

还有一些其他有用的功能参数,比如:vet和fmt,后者是大招啊。

依赖管理

默认情况下go get都会去下载最新的代码然后构建,除非被中断。

在开发环境下这个没什么影响,但肯定不适用于生产环境。

略去数十字(vendoring啥意思..),不喜欢这种做法,推荐gopkg.in

gopkg.in/user/pkg.v3 -> github.com/user/pkg (branch/tag v3, v3.N, or v.3.N.M)

命名

程序其实就是一堆名字的构成,取名还是挺花时间和成本的。

简单来说,长的名字浪费空间,而且在可读性方面很重要,好的名字一眼就能看意图。

多花点时间,取一些简短和可理解的名字吧。

命名风格

  • 使用驼峰camelCase,而不是下划线_underscores连接。
  • 局部变量尽量短,短,短,1-2 个字符的情况很常见。
  • 包的名字一般来说,都是小写字母。
  • 全局(公开)变量

不建议这样:

  • bytes.Buffer,不要 bytes.ByteBuffer
  • zip.Reader,不要 zip.ZipReader
  • errors.New,不要 errors.NewError
  • r 不要用在 bytesReader
  • i 不要用在 loopIterator

文档

文档位置在模块或者导出的名字前面:

// Join concatenates the elements of elem to create a single string.
// The separator string sep is placed between elements in the resulting string.
func Join(elem []string, sep string) string {

通过godoc在 web 查看该函数时候,文档位置位于函数原型下方(图略去)。

请用英语书写文档句子和段落(无视我大汉字啊)

// Join concatenates…         good
// This function…             bad

包文档位于模块最上面:

// Package fmt…
	package fmt

关于 Go docs 请参考:http://talks.golang.org/2014/godoc.org

最后,这是一份演讲稿,相对来说内容偏少,随意看看吧。。

END

翻译-如何组织Go代码was originally published by smallfish atsmallfish blogon November 06, 2014.

原文链接: http://chenxiaoyu.org/2014/11/06/organizing-go-code.html

0     0

我要给这篇文章打分:

可以不填写评论, 而只是打分. 如果发表评论, 你可以给的分值是-5到+5, 否则, 你只能评-1, +1两种分数. 你的评论可能需要审核.

评价列表(0)