How to Write GO Code 中文版

How to Write GO Code 中文版

  • 说明

    • 官方原文
    • 本文按个人理解进行意译,水平有限,难免有错或偏差,欢迎批评指正
  • 目录

    • Introduction

    • Code Organization

      • overview
      • workspace
      • the GOPATH environment variable
      • import paths
      • your first program
      • your first library
      • package names
    • Testing

    • remote packages

    • what`s next

    • getting help

introduction

  • Go语言要求使用指定的方法组织代码。
  • 需要认真阅读这份文档。

Code Organization

overview

  • 通常来说Go开发者将他所有的源代码放到一个单独的工作目录中

  • 一个工作目录中包含多版本控制仓库

  • 每个仓库包含一个或者多个包

  • 每个包在一个单路的目录中包含一个或者多个GO源代码文件

  • 到包的路径决定了它import的路径

需要注意,这一点,与其他语言编程环境中每一个项目都放在一个分开的单独工作目录并且每个工作目录都有一个仓库版本控制,是不同的

workspace

一个工作目录是一个层次结构目录,在其根目录包含以下三个目录

  • src 包含Go语言的源代码文件
  • pkg 包含包对象
  • bin 包含可执行文件

go工具构建源代码并将生成的二进制文件放到 pkg 和 bin 目录中。

src 子目录通常包含多版本控制仓库来追踪一个或者多个源包的开发过程。

下面是个实际中的关于工作空间的简要例子:

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
    golang.org/x/image/
        .git/                      # Git repository metadata
    bmp/
        reader.go              # package source
        writer.go              # package source
    ... (many more repositories and packages omitted) ...

上面的结构树展示了一个工作空间包含两个仓库(example和image)。example库包含两个可执行目录(hello和outyet)和一个库(stringutil)。image仓库包含bmp包和几个其他包

一个典型的工作空间包含了内含许多包和命令的仓库。绝大多数的go开发者将他们的源代码和依赖都放到一个工作空间中。

命令和库 是从不同的源码包构建而来。

the GOPATH environment variable

GOPATH 环境变量指明了工作空间的位置。它默认是在你的主目录中的一个名为go的目录, 所以在Linux下就是$HOME/go, 在plan9下就是$home/go, 在Windows下就是%USERPROFILE%/go(通过是C:\Users\YourName\go).

如果想在一个不同的目录下工作,需要 设置 GOPATH 到想指定的目录.(另一个通常的设置是设置 GOPATH=$HOME).<strong>需要注意的是 GOPATH 和 go的安装目录不能相同</strong>.

为了方便,添加工作空间的 bin 子目录到path:

$ export PATH=$PATH:$(go env GOPATH)/bin

为了简短一点,上面脚本在本文末使用 $GOPATH 替换 $(go env GOPATH).

要学习更多关于GOPATH环境变量相关的信息,查看 go help gopath

要使用通用工作空间位置,查看 GOPATH 环境变量

import paths

一个导入路径 import path 是唯一性地标志一个包的字符串。一个包的import path对应它在工作空间中的位置或者一个远程仓库.

标准库中的包通常都给定一个比如 "fmt"或者"net/http"这样简短的import path. 对于你自己的包,需要选一个不会跟未来被添加到标准库或者其他拓展库的命名冲突的基础路径。

我们选择 github.com/user 作为我们的基础路径,然后在工作空间中创建爱你一个目录来保存源代码:

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

your first program

为了编译和运行一个简单的程序,首先选一个包路径(我们将使用 github.com/user/hello)然后在工作目录中创建一个对应的包目录

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

然后,在那个目录里面创建一个文件,命名为 hello.go,并把下面的代码放上去:

package main

import "fmt"

func main(){
    fmt.Printf("Hello, world.\n")
}


现在,可以使用go tool 来 build 并且安装上面的程序了:

$ go install github.com/user/hello

你可以在你系统的任务地方运行上面的命令. go tool 会根据 GOPATH 指明的工作空间到 github.com/user/hello 包中找到源代码.

如果从包目录中运行 go install,你可以忽略掉包的路径:

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

上面的命令将会构建 hello 命令,产生一个可执行二进制文件。然后将二进制文件以hello名字安装到工作空间的 bin 目录下(在 Windows下是 hello.exe)。在我们的例子中就是 $GOPATH/bin/hello, 也就是 $HOME/go/bin/hello.

go 工具只有在产生错误时才打印输出,所以如果上面的命令执行之后没有产生任何打印输出,那就是执行成功了。

现在可以通过全路径运行命令:

$ $GOPATH/bin/hello
Hello, world

或者也可以添加 $GOPATH/bin到你的 PATH,然后运行二进制文件就可以执行命令了:

$ hello
Hello, world

your first library

选择一个包路径(在这我们将使用 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

上面的命令不会产生一个文件。如果想要产生文件,必须使用 go install,这样的话会在工作空间的 pkg 的目录中产生一个包对象。

确认 stringutil 包被构建之后,更改hello.go(在$GOPATH/src/github.com/user/hello目录下)来使用它

package main

import (
    "fmt"

    "github.com/user/stringutil"
)

func main() {
    fmt.Printf(stringutil.Reverse("!oG ,olleH"))
}

任何时候 go tool 安装了一个包或者二进制文件, 包或者二进制文件里面的所有依赖也会被安装,所以当安装 hello 程序, stringutil 包也同时会自动被安装

$go install github.com/user/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 可以找到包对象并避免对包进行不必要的重编译。linux_amd64可以帮助交叉编译,并反映操作系统和系统的结构。

Go 命令可执行文件是静态链接的:运行 Go 程序不需要包对象的存在

package names

Go 源文件的第一条语句必须是:

package name

name 是包的导入默认名字(其他文件导入这个包时使用的名称)(一个包中的所有文件都必须是相同的name

Go 的惯例是包名是导入路径的最后一个元素。如果被导入的包是cryto/rot13那么包的名字应该是 rot13

可执行命令必须使用总是使用 package main。

被链接到一个单个二进制文件的所有包,这些包的名称不要求名字唯一性,但是包的导入路径要求内唯一性(文件完整名称)

查看 Effective Go 来了解更多信息

Testing

Go 有一个由 go test 命令和 testing 包组成的轻量级的测试框架.

创建一个以 _test.go为文件名后缀的文件,文件中包含名为 TestXXX 的签名 func (t *testing.T)的函数,通过这样的方式来编写测试。测试框架运行每一个这样的函数,如果函数调用类似 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 github.com/user/stringutil
ok github.com/user/stringutil 0.165s

另外,如果你是在包的目录下的话,不用跑上面的命令,直接跑下面的命令即可

$ go test
ok github.com/user/stringutil 0.165s

运行 go helo test 以及查看 testing package documentation来了解更多信息

remote packages

一个导入路径可以描述如何通过使用比如git或者marcurial这样的版本控制系统来获取包的源代码。go tool 使用这个特性来自动从远处仓库获取包。举个栗子,在这个文档中描述的包同时是一个托管在 github.com/golang/example 的Git仓库。如果在包的导入路径中包含这个仓库的URL,那么, go get 会自动地获取,构建,然后安装它:

$ go get github/com/golang/example/hello
$ $GOPATH/bin/hello
Hello, Go examples?

如果指定的包没有出现在工作空间中,go get 将会把该指定的包放置通过GOPATH指定的第一个工作空间中。(如果该包早已经存在将要被放置的工作空间中,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上托管的hello命令依赖于同一个存储库中的stringutil包. hello.go 文件中的导入使用相同的导入路径约定,因此 go get 也可以找到并安装依赖的包。

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

这个约定是让你的go 包可以被其他go开发者使用的最简单的方法。Go wikigodoc.org提供里go的拓展项目.

想要了解更多的关于使用 go tool 来获取远程仓库的信息,查看go help importpath

what`s next

看一下 Effective Go

看一下 A Tour of Go

看一下 documentation page

getting help

如果需要实时帮助,访问Freenode

官方关于go的探讨的邮件列表在Go Nuts

有bug想上报?到Go issue tracker

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容